diff --git a/.vscode/settings.json b/.vscode/settings.json index 3bc23c0..7acf05b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,20 +7,29 @@ "Ballas", "ballasout", "BLAINECOUNTY", + "BODHI", "Callout", "Callouts", "CARBINERIFLE", "Cayo", + "chicold", + "Decryptor", "Dekokiyo", "DOUBLEACTION", "Driveable", + "Encryptor", "famca", "famdnf", "famfor", "FBISWAT", + "Gusenberg", "Hawick", "HEAVYPISTOL", + "intupperphotography", + "Jakowski", + "Lazlow", "LCPDFR", + "lestercrest", "LOSSANTOS", "LOSSANTOSCOUNTY", "lossantospolicedept", @@ -28,18 +37,23 @@ "LSSD", "lxml", "Mantain", + "nervousron", "NORTHYANKTON", "openpyxl", "Paleto", "Perico", "Perro", + "POLICEOLD", "POLICET", "Puerta", + "Ragdoll", "roadcone", "Rockstar", "SNIPERRIFLE", "Snowlight", + "tendtodead", "Tongva", + "UNSTREAMED", "Vinewood", "voyeurizing", "Yankton" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 06922f5..3fdc100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -22,9 +22,19 @@ } }, { - "label": "Release-Zip", + "label": "Dev-Confused", + "type": "shell", + "command": "powershell -ExecutionPolicy Bypass .\\DevelopBuild-Confused.ps1", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Release-Confused", "type": "shell", - "command": "powershell -ExecutionPolicy Bypass .\\ReleaseZip.ps1", + "command": "powershell -ExecutionPolicy Bypass .\\ReleaseBuild-Confused.ps1", "problemMatcher": [], "group": { "kind": "build", @@ -32,14 +42,14 @@ } }, { - "label": "Format", + "label": "Release-Zip", "type": "shell", - "command": "dotnet format DynamicLSPDFR/DynamicLSPDFR.csproj", + "command": "powershell -ExecutionPolicy Bypass .\\ReleaseZip-Confused.ps1", "problemMatcher": [], "group": { "kind": "build", - "isDefault": false + "isDefault": true } - } + }, ] } \ No newline at end of file diff --git a/Archive/ManualSirenLevel.cs b/Archive/ManualSirenLevel.cs new file mode 100644 index 0000000..b3c5c92 --- /dev/null +++ b/Archive/ManualSirenLevel.cs @@ -0,0 +1,46 @@ +namespace DynamicLSPDFR.Debug; + +internal static class ManualSiren +{ + internal static int Level = 0; + + internal static void Initialize() + { + GameFiber.StartNew(() => + { + while (true) + { + GameFiber.Yield(); + if (Level > 0) + { + Level--; + GameFiber.Wait(100); + } + } + }); + + GameFiber.StartNew(Update); + } + + internal static void Update() + { + while (true) + { + GameFiber.Yield(); + Game.DisplayHelp(Level.ToString()); + } + } + + internal static void AddValue() + { + GameFiber.StartNew(() => + { + GameFiber.Yield(); + if (Level < 100) + { + Level++; + GameFiber.Wait(100); + } + }); + } +} \ No newline at end of file diff --git a/DevelopBuild-Confused.ps1 b/DevelopBuild-Confused.ps1 new file mode 100644 index 0000000..5f69224 --- /dev/null +++ b/DevelopBuild-Confused.ps1 @@ -0,0 +1,15 @@ +Write-Host "-------- Build as the Develop Edition --------" -ForegroundColor DarkMagenta +Write-Host "-------- Comfused Enabled --------" -ForegroundColor Green +Start-Sleep -Milliseconds 250 +.\PowerShell\Dev.ps1 +Write-Host "-------- Build Completed --------" -ForegroundColor Green +Write-Host "-------- Start Obfuscation --------" -ForegroundColor Blue +Start-Sleep -Milliseconds 250 +.\PowerShell\Obfuscation.ps1 +Write-Host "-------- Obfuscation Completed --------" -ForegroundColor Green +Write-Host "-------- Copy Files to GTA5 --------" -ForegroundColor Blue +Start-Sleep -Milliseconds 250 +.\PowerShell\CopyFiles-Confuse.ps1 +Start-Sleep -Milliseconds 250 +Write-Host "-------- Copy Completed --------" -ForegroundColor Green +.\PowerShell\Completed.ps1 \ No newline at end of file diff --git a/DevelopBuild.ps1 b/DevelopBuild.ps1 index 931d770..6f2d110 100644 --- a/DevelopBuild.ps1 +++ b/DevelopBuild.ps1 @@ -1,11 +1,9 @@ Write-Host "-------- Build as the Develop Edition --------" -ForegroundColor DarkMagenta +Write-Host "-------- Comfused Disabled --------" -ForegroundColor Red Start-Sleep -Milliseconds 250 .\PowerShell\Dev.ps1 Write-Host "-------- Build Completed --------" -ForegroundColor Green -Write-Host "-------- Start Obfuscation --------" -ForegroundColor Blue -Start-Sleep -Milliseconds 250 -.\PowerShell\Obfuscation.ps1 -Write-Host "-------- Obfuscation Completed --------" -ForegroundColor Green +Write-Host "-------- Skip Obfuscation --------" -ForegroundColor Blue Write-Host "-------- Copy Files to GTA5 --------" -ForegroundColor Blue Start-Sleep -Milliseconds 250 .\PowerShell\CopyFiles.ps1 diff --git a/Document/Animations.txt b/Document/Animations.txt index 26a3e8d..3c1ec4b 100644 --- a/Document/Animations.txt +++ b/Document/Animations.txt @@ -39,4 +39,8 @@ amb@world_human_cop_idles@female@idle_enter 運ぶときの抱えるアニメーション的な anim@heists@box_carry@ -- idle \ No newline at end of file +- idle + +写真 +amb@world_human_paparazzi@male@base +- base \ No newline at end of file diff --git "a/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\344\270\211\345\274\276\347\224\250Readme.txt" "b/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\344\270\211\345\274\276\347\224\250Readme.txt" new file mode 100644 index 0000000..f91b738 --- /dev/null +++ "b/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\344\270\211\345\274\276\347\224\250Readme.txt" @@ -0,0 +1,60 @@ +===================================================================================== +                                    + このプラグインはベータ版です。バグ検証はしておりますが、万が一重大なバグが発生して、 + プレイヤーに対し損害が発生したとしても、開発者は一切の責任を負いません。     + また、バグが発生した場合は、バグ報告のご協力をお願い致します。         + バグ報告先は、ロケット霊夢様の快諾を得て、LSPDFRコミュニティ(JP)内の専用スレッドへ + ご送信ください。開発者が直接対応させていただきます。 +                                    +===================================================================================== + +Copyright 2023 DekoKiyo + +LSPDFRコミュニティ(JP)配布用 DynamicLSPDFR 開発版Ver.0.3.0.0をDLして頂きありがとうございます。 +導入前に以下の注意をお読みください。 + +【注意】 +1. このファイルはDekoKiyo(以下開発者)の意思により配布しています。このサーバーへ参加しているかを問わず、他人に二次配布は行わないでください。 +2. このファイルは著作権法に基づきソースコードは公開されていません。 + 逆コンパイルなどでソースコードを不正に入手する行為は認められていません。 + 不正流出防止のためにファイルの暗号化はしていますが、 + 万が一、ソースコードの不正流出またはそれに類する行為が確認された場合は、このサーバーでの配布を停止します。 + 発覚したらブチギレだぞヽ(`Д´#)ノ ムキー!! +3. 質問chや僕のDMにパスワード関連の問い合わせはしないでください。 + したらちゃぶ台投げるぞ(ノ`Д´)ノ彡┻━┻ + +【説明】 +DynamicLSPDFRはLCPDFR.comにて公開されているLSPDFR用プラグインです。 +特徴として、多言語対応、独自の乱数生成アルゴリズムを搭載しています。 +また、このデータではコールアウトを12個追加します。(完成度が高いとは言っていない。) + +このデータはVer.0.3.0.0となっていますが、もしかしたら正式リリース1.0.0.0になるかもしれないです。 +結構頑張って作ってるので使ってくれるだけでも嬉しいです(*´∀`) +ってなわけなんですが、一つ注意です。上記の通りバグを含んでいる可能性があります。 +万が一これを導入してLSPDFRがクラッシュした場合はLSPDFRコミュニティ(JP)内の専用スレッドを用意しているのでそちらにバグ報告をお願い致します。 +何をしたらクラッシュしたのかとログファイル(GTA5.exeがあるディレクトリの中にあるRAGEPluginHook.log)を添付してくださいますと非常に助かります。 + +【追加機能】 +既存の機能については公式Wikiを御覧ください→ (https://github.com/Dekokiyo/DynamicLSPDFR/wiki) +・コールアウト「銀行強盗」を追加 +・コールアウト「ひき逃げ」を追加 +・コールアウト「危険人物を発見」を追加 + +正式版はこちらでDL可能です。 +https://www.lcpdfr.com/downloads/gta5mods/scripts/43022-dynamic-lspdfr/ + +開発者SNS +Twitter: https://twitter.com/DekoKiyomori +GitHub: https://github.com/DekoKiyo + + + + + + + + + + + +パスワード: 3DLS417 \ No newline at end of file diff --git "a/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\345\233\233\345\274\276\347\224\250Readme.txt" "b/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\345\233\233\345\274\276\347\224\250Readme.txt" new file mode 100644 index 0000000..e68c317 --- /dev/null +++ "b/Document/Readme/LSPDFR\343\202\263\343\203\237\343\203\245\343\203\213\343\203\206\343\202\243\351\205\215\345\270\203\347\254\254\345\233\233\345\274\276\347\224\250Readme.txt" @@ -0,0 +1,79 @@ +===================================================================================== +                                    + このプラグインはベータ版です。バグ検証はしておりますが、万が一重大なバグが発生して、 + プレイヤーに対し損害が発生したとしても、開発者は一切の責任を負いません。     + また、バグが発生した場合は、バグ報告のご協力をお願い致します。         + バグ報告先は、ロケット霊夢様の快諾を得て、LSPDFRコミュニティ(JP)内の専用スレッドへ + ご送信ください。開発者が直接対応させていただきます。 +                                    +===================================================================================== + +Copyright 2023 DekoKiyo + +LSPDFRコミュニティ(JP)配布用 DynamicLSPDFR 開発版Ver.0.3.0.0をDLして頂きありがとうございます。 +導入前に以下の注意をお読みください。 +ただそ、注意と説明は前回の配布と文面は同じです。読み飽きた方は飛ばしてどうぞ + + +【注意】 +1. このファイルはDekoKiyo(以下開発者)の意思により配布しています。このサーバーへ参加しているかを問わず、他人に二次配布は行わないでください。 +2. このファイルは著作権法に基づきソースコードは公開されていません。 + 逆コンパイルなどでソースコードを不正に入手する行為は認められていません。 + 不正流出防止のためにファイルの暗号化はしていますが、 + 万が一、ソースコードの不正流出またはそれに類する行為が確認された場合は、このサーバーでの配布を停止します。 + 発覚したらブチギレだぞヽ(`Д´#)ノ ムキー!! +3. 質問chや僕のDMにパスワード関連の問い合わせはしないでください。 + したらちゃぶ台投げるぞ(ノ`Д´)ノ彡┻━┻ + + +【説明】 +DynamicLSPDFRはLCPDFR.comにて公開されているLSPDFR用プラグインです。 +特徴として、多言語対応、独自の乱数生成アルゴリズムを搭載しています。 +また、このデータではコールアウトを12個追加します。(完成度が高いとは言っていない。) + +このデータはVer.0.3.0.0となっていますが、もしかしたら正式リリース1.0.0.0になるかもしれないです。 +結構頑張って作ってるので使ってくれるだけでも嬉しいです(*´∀`) +ってなわけなんですが、一つ注意です。上記の通りバグを含んでいる可能性があります。 +万が一これを導入してLSPDFRがクラッシュした場合はLSPDFRコミュニティ(JP)内の専用スレッドを用意しているのでそちらにバグ報告をお願い致します。 +何をしたらクラッシュしたのかとログファイル(GTA5.exeがあるディレクトリの中にあるRAGEPluginHook.log)を添付してくださいますと非常に助かります。 + + +【開発者からの切実なお願い】 +お願いします!!!! +どうかLCPDFR.comの配布ページにレビューを付けてください!!! (できれば高評価) +思いつかなかったら「This is the one of best of LSPDFR plugins! I give him my all of money!」でも構いません。 + + +【前回の配布からの追加機能】 +既存の機能については公式Wikiを御覧ください→ (https://github.com/Dekokiyo/DynamicLSPDFR/wiki) +・検視官システムを追加しました。Kキーで呼び出せます。日本語対応 +・検視官レポートを追加しました。Uキーで開けます。が、もしかしたらバグってるかもしれません。 + また、言語を変更しても翻訳が更新されない場合があります。 + + +【前回の追加機能】 +・コールアウト「銀行強盗」を追加 +・コールアウト「ひき逃げ」を追加 +・コールアウト「危険人物を発見」を追加 + + +正式版はこちらでDL可能です。 +レビューしてね!!!!! お願い!!!!! +https://www.lcpdfr.com/downloads/gta5mods/scripts/43022-dynamic-lspdfr/ + + +開発者SNS +Twitter: https://twitter.com/DekoKiyomori +GitHub: https://github.com/DekoKiyo + + + + + + + + + + + +パスワード: KadaiOwaranTasukete \ No newline at end of file diff --git "a/Document/\343\202\250\343\203\251\343\203\274\343\202\263\343\203\274\343\203\211\344\270\200\350\246\247.txt" "b/Document/\343\202\250\343\203\251\343\203\274\343\202\263\343\203\274\343\203\211\344\270\200\350\246\247.txt" index ccaf6b4..bf76394 100644 --- "a/Document/\343\202\250\343\203\251\343\203\274\343\202\263\343\203\274\343\203\211\344\270\200\350\246\247.txt" +++ "b/Document/\343\202\250\343\203\251\343\203\274\343\202\263\343\203\274\343\203\211\344\270\200\350\246\247.txt" @@ -1,5 +1,21 @@ +10: GTA5のバージョンチェック時にエラー +11: LSPDFRのバージョンチェック時にエラー +12: RPHのバージョンチェック時にエラー +13: RAGENativeUIのバージョンチェック時にエラー +14: Newtonsoft.Jsonのバージョンチェック時にエラー +30: 交通切符のXmlの読み込みに失敗 50: コールアウトの開始時の初期化に失敗 51: コールアウトの開始時、Pedの生成に失敗 52: コールアウトの開始時、Vehicleの生成に失敗 53: コールアウトの開始時、Blipの生成に失敗 -60: コールアウトの進行中、エラーが発生 \ No newline at end of file +60: コールアウトの進行中、エラーが発生 +65: ロード時に、セーブファイルの中身が無い (無効化) +66: ロード時に、データの復号に失敗 +67: ロード時に、読み取り作業1でエラー +68: ロード時に、読み取り作業2でエラー +69: セーブ時に、書き出し作業1でエラー +70: セーブ時に、書き出し作業2でエラー +71: セーブ時に、暗号化に失敗 +72: セーブ時に、ファイルへの保存で失敗 +73: 読み取り時にキーが見つからない +74: 読み取り時に読み取りに失敗 \ No newline at end of file diff --git "a/Document/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253\344\272\210\345\202\231\350\273\215.txt" "b/Document/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253\344\272\210\345\202\231\350\273\215.txt" new file mode 100644 index 0000000..714fd9d --- /dev/null +++ "b/Document/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253\344\272\210\345\202\231\350\273\215.txt" @@ -0,0 +1,10 @@ +; Open Traffic Tickets Menu Key +OpenTrafficTicketsMenuKey = U +OpenTrafficTicketsMenuKey-Modifier = LControlKey + +[TrafficTickets] +; Limit points of seize suspect vehicle +LimitOfSeize = 10 +Unit = $ +; If it's true, the unit is displayed in right. +RightUnitPosition = false \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/CalloutBase.cs b/DynamicLSPDFR/Callouts/CalloutBase.cs index 1ea8b4d..5adecd6 100644 --- a/DynamicLSPDFR/Callouts/CalloutBase.cs +++ b/DynamicLSPDFR/Callouts/CalloutBase.cs @@ -2,4 +2,183 @@ namespace DynamicLSPDFR.Callouts; internal abstract class CalloutBase : Callout { + internal abstract bool IsEnable(); + internal abstract string TranslateKey(); + internal static List CalloutItems = new(); + + internal static void InitializeCallouts() + { + if (ClientSettings.StolenCarPursuitIsEnabled) + { + Functions.RegisterCallout(typeof(StolenCarPursuit)); + var item = new UIMenuItem(Translation.GetString("StolenCarPursuit")); + item.Activated += (m, i) => Functions.StartCallout("StolenCarPursuit"); + CalloutItems.Add(item); + Logger.Info("\"Stolen Car Pursuit\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.GangShootoutIsEnabled) + { + Functions.RegisterCallout(typeof(GangShootout)); + var item = new UIMenuItem(Translation.GetString("GangShootout")); + item.Activated += (m, i) => Functions.StartCallout("GangShootout"); + CalloutItems.Add(item); + Logger.Info("\"Gang Shootout\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.CriminalFoundIsEnabled) + { + Functions.RegisterCallout(typeof(WantedCriminalFound)); + var item = new UIMenuItem(Translation.GetString("WantedCriminalFound")); + item.Activated += (m, i) => Functions.StartCallout("WantedCriminalFound"); + CalloutItems.Add(item); + Logger.Info("\"Wanted Criminal Found\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.DynamicPursuitIsEnabled) + { + Functions.RegisterCallout(typeof(DynamicPursuit)); + var item = new UIMenuItem(Translation.GetString("DynamicPursuit")); + item.Activated += (m, i) => Functions.StartCallout("DynamicPursuit"); + CalloutItems.Add(item); + Logger.Info("\"Dynamic Pursuit\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.StoreRobberyIsEnabled) + { + Functions.RegisterCallout(typeof(StoreRobbery)); + var item = new UIMenuItem(Translation.GetString("StoreRobbery")); + item.Activated += (m, i) => Functions.StartCallout("StoreRobbery"); + CalloutItems.Add(item); + Logger.Info("\"Store Robbery\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.SushiIsEnabled) + { + Functions.RegisterCallout(typeof(SushiTerrorism)); + var item = new UIMenuItem(Translation.GetString("SushiTerrorism")); + item.Activated += (m, i) => Functions.StartCallout("SushiTerrorism"); + CalloutItems.Add(item); + Logger.Info("\"Sushi Terrorism\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.StolenMoneyTruckIsEnabled) + { + Functions.RegisterCallout(typeof(StolenMoneyTruck)); + var item = new UIMenuItem(Translation.GetString("StolenMoneyTruck")); + item.Activated += (m, i) => Functions.StartCallout("StolenMoneyTruck"); + CalloutItems.Add(item); + Logger.Info("\"Stolen Money Truck\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.StreetFightIsEnabled) + { + Functions.RegisterCallout(typeof(StreetFight)); + var item = new UIMenuItem(Translation.GetString("StreetFight")); + item.Activated += (m, i) => Functions.StartCallout("StreetFight"); + CalloutItems.Add(item); + Logger.Info("\"Street Fight\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.BankRobberyIsEnabled) + { + Functions.RegisterCallout(typeof(BankRobbery)); + var item = new UIMenuItem(Translation.GetString("BankRobbery")); + item.Activated += (m, i) => Functions.StartCallout("BankRobbery"); + CalloutItems.Add(item); + Logger.Info("\"Bank Robbery\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.HitAndRunIsEnabled) + { + Functions.RegisterCallout(typeof(HitAndRun)); + var item = new UIMenuItem(Translation.GetString("HitAndRun")); + item.Activated += (m, i) => Functions.StartCallout("HitAndRun"); + CalloutItems.Add(item); + Logger.Info("\"Hit And Run\" registered!", "DynamicLSPDFR-Callout"); + } + if (ClientSettings.DangerousFoundIsEnabled) + { + Functions.RegisterCallout(typeof(FoundDangerousPerson)); + var item = new UIMenuItem(Translation.GetString("FoundDangerousPerson")); + item.Activated += (m, i) => Functions.StartCallout("FoundDangerousPerson"); + CalloutItems.Add(item); + Logger.Info("\"Found Dangerous Person\" registered!", "DynamicLSPDFR-Callout"); + } + + if (CalloutItems.Count is not 0) + { + CalloutsMenu.Callouts.AddItems(CalloutItems); + } + else + { + ContextMenu.CalloutsList.EnableItem(false); + } + } + + internal static void UpdateTranslate() + { + if (CalloutItems.Count is 0) return; + CalloutItems.Clear(); + CalloutsMenu.Callouts.Clear(); + + if (ClientSettings.StolenCarPursuitIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("StolenCarPursuit")); + item.Activated += (m, i) => Functions.StartCallout("StolenCarPursuit"); + CalloutItems.Add(item); + } + if (ClientSettings.GangShootoutIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("GangShootout")); + item.Activated += (m, i) => Functions.StartCallout("GangShootout"); + CalloutItems.Add(item); + } + if (ClientSettings.CriminalFoundIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("WantedCriminalFound")); + item.Activated += (m, i) => Functions.StartCallout("WantedCriminalFound"); + CalloutItems.Add(item); + } + if (ClientSettings.DynamicPursuitIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("DynamicPursuit")); + item.Activated += (m, i) => Functions.StartCallout("DynamicPursuit"); + CalloutItems.Add(item); + } + if (ClientSettings.StoreRobberyIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("StoreRobbery")); + item.Activated += (m, i) => Functions.StartCallout("StoreRobbery"); + CalloutItems.Add(item); + } + if (ClientSettings.SushiIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("SushiTerrorism")); + item.Activated += (m, i) => Functions.StartCallout("SushiTerrorism"); + CalloutItems.Add(item); + } + if (ClientSettings.StolenMoneyTruckIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("StolenMoneyTruck")); + item.Activated += (m, i) => Functions.StartCallout("StolenMoneyTruck"); + CalloutItems.Add(item); + } + if (ClientSettings.StreetFightIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("StreetFight")); + item.Activated += (m, i) => Functions.StartCallout("StreetFight"); + CalloutItems.Add(item); + } + if (ClientSettings.BankRobberyIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("BankRobbery")); + item.Activated += (m, i) => Functions.StartCallout("BankRobbery"); + CalloutItems.Add(item); + } + if (ClientSettings.HitAndRunIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("HitAndRun")); + item.Activated += (m, i) => Functions.StartCallout("HitAndRun"); + CalloutItems.Add(item); + } + if (ClientSettings.DangerousFoundIsEnabled) + { + var item = new UIMenuItem(Translation.GetString("FoundDangerousPerson")); + item.Activated += (m, i) => Functions.StartCallout("FoundDangerousPerson"); + CalloutItems.Add(item); + } + CalloutsMenu.Callouts.AddItems(CalloutItems); + } } \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/CalloutList.cs b/DynamicLSPDFR/Callouts/CalloutList.cs deleted file mode 100644 index 405a33f..0000000 --- a/DynamicLSPDFR/Callouts/CalloutList.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace DynamicLSPDFR.Callouts; - -internal static class CalloutList -{ - internal static List RegisteredCallouts = new(); - - internal static Dictionary AllCallouts = new() - { - { typeof(StolenCarPursuit), "StolenCarPursuit" }, - { typeof(GangShootout), "GangShootout" }, - { typeof(WantedCriminalFound), "WantedCriminalFound" }, - { typeof(DynamicPursuit), "DynamicPursuit" }, - // { typeof(PanicButton), "PanicButton" }, - { typeof(StoreRobbery), "StoreRobbery" }, - { typeof(SushiTerrorism), "SushiTerrorism" }, - { typeof(StolenMoneyTruck), "StolenMoneyTruck" }, - { typeof(StreetFight), "StreetFight" }, - // { typeof(PacificBankHeist), "PacificBankHeist" }, - }; - - internal static void RegisterCallouts() - { - foreach (var c in AllCallouts) - { - Functions.RegisterCallout(c.Key); - Logger.Info(nameof(c.Key), "DynamicLSPDFR-Callout"); - } - - // for (int i = 0; i < AllCallouts.Length; i++) - // { - // if (ClientSettings.CalloutsEnable[i]) - // { - // Functions.RegisterCallout(AllCallouts[i].Item1); - // Logger.Info($"\"{AllCallouts[i].Item2}\" was successfully loaded!", "DynamicLSPDFR"); - // var item = new UIMenuItem(Translation.GetString(AllCallouts[i].Item2)); - // DynamicMenu.CalloutItems.Add(item); - // RegisteredCallouts.Add(AllCallouts[i].Item2); - // } - // else Logger.Info($"\"{AllCallouts[i].Item2}\" was disabled to load.", "DynamicLSPDFR"); - // } - // if (DynamicMenu.CalloutItems.Count is not 0) - // { - // DynamicMenu.StartCalloutsListMenu.AddItems(DynamicMenu.CalloutItems); - // for (int i = 0; i < RegisteredCallouts.Count; i++) DynamicMenu.CalloutItems[i].Activated += (m, item) => Functions.StartCallout(RegisteredCallouts[i]); - // } - // if (RegisteredCallouts.Count is 0) DynamicMenu.CalloutsListItem.EnableItem(false); - } - - // internal static void UpdateCalloutsLanguage() - // { - // for (int i = 0; i < DynamicMenu.CalloutItems.Count(); i++) DynamicMenu.CalloutItems[i].Text = Translation.GetString(RegisteredCallouts[i]); - // } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/FoundDangerousPerson/FoundDangerousPerson.cs b/DynamicLSPDFR/Callouts/FoundDangerousPerson/FoundDangerousPerson.cs new file mode 100644 index 0000000..99c213b --- /dev/null +++ b/DynamicLSPDFR/Callouts/FoundDangerousPerson/FoundDangerousPerson.cs @@ -0,0 +1,187 @@ +namespace DynamicLSPDFR.Callouts; + +[CalloutInfo("FoundDangerousPerson", CalloutProbability.Low)] +internal class FoundDangerousPerson : CalloutBase +{ + internal override bool IsEnable() => ClientSettings.DangerousFoundIsEnabled; + internal override string TranslateKey() => "FoundDangerousPerson"; + + private Dictionary suspects = new(); + private Vehicle vehicle; + private LHandle pursuit; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(RandomNumber.Instance.Next(500, 1200))); + private FoundDangerousPersonData.Team member; + private WeaponHash[] driverWeapons = new[] { WeaponHash.AdvancedRifle, WeaponHash.AssaultRifle, WeaponHash.CarbineRifle, WeaponHash.Smg, WeaponHash.AssaultSMG }; + private WeaponHash[] paxWeapons = new[] { WeaponHash.Pistol, WeaponHash.APPistol, WeaponHash.MicroSMG, WeaponHash.Smg, WeaponHash.AssaultSMG }; + private bool PursuitBegan = false, go = false; + private int sno = RandomNumber.Instance.Next(2); + + public override bool OnBeforeCalloutDisplayed() + { + CalloutMessage = Translation.GetString(TranslateKey()); + CalloutPosition = SpawnPoint; + ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 100f); + Functions.PlayScannerAudioUsingPosition("ATTENTION_ALL_UNITS WE_HAVE DL_CRIME_SUSPECT_RESISTING_ARREST_01 IN_OR_ON_POSITION UNITS_RESPOND_CODE_99", SpawnPoint); + return base.OnBeforeCalloutDisplayed(); + } + + public override bool OnCalloutAccepted() + { + Logger.Info("[DynamicLSPDFR] Callout \"Found Dangerous Person\" was started."); + + MessageExtensions.SendDispatchMessage(Translation.GetString("FoundDangerousPersonDesc"), TranslateKey()); + + try + { + member = (FoundDangerousPersonData.Team)RandomNumber.Instance.Next((int)FoundDangerousPersonData.Team.None); + + var vModel = new Model(FoundDangerousPersonData.Data[member].Item1); + vModel.LoadAndWait(); + + vehicle = new(vModel, SpawnPoint); + if (vehicle && vehicle.IsValid()) + { + vehicle.IsPersistent = true; + } + for (int i = 0; i < FoundDangerousPersonData.Data[member].Item2.Count; i++) + { + var model = FoundDangerousPersonData.Data[member].Item2[i]; + var p = new Ped(model, Vector3.Zero, 0f); + if (p && p.IsValid()) + { + switch (model) + { + case "player_zero": + Functions.GetPersonaForPed(p).Forename = "Michael"; + Functions.GetPersonaForPed(p).Surname = "De Santa"; + Functions.GetPersonaForPed(p).Birthday = new(1965, 2, 19); + break; + case "player_one": + Functions.GetPersonaForPed(p).Forename = "Franklin"; + Functions.GetPersonaForPed(p).Surname = "Clinton"; + Functions.GetPersonaForPed(p).Birthday = new(1988, 4, 23); + break; + case "player_two": + Functions.GetPersonaForPed(p).Forename = "Trevor"; + Functions.GetPersonaForPed(p).Surname = "Phillips"; + Functions.GetPersonaForPed(p).Birthday = new(1968, 11, 14); + break; + case "ig_nervousron": + Functions.GetPersonaForPed(p).Forename = "Ron"; + Functions.GetPersonaForPed(p).Surname = "Jakowski"; + Functions.GetPersonaForPed(p).Birthday = new(1964, 6, 4); + break; + case "ig_wade": + Functions.GetPersonaForPed(p).Forename = "Wade"; + Functions.GetPersonaForPed(p).Surname = "Hebert"; + break; + case "ig_lestercrest": + Functions.GetPersonaForPed(p).Forename = "Lester"; + Functions.GetPersonaForPed(p).Surname = "Crest"; + break; + } + p.IsPersistent = true; + p.BlockPermanentEvents = true; + if (i is 0) + { + p.Inventory.GiveNewWeapon(driverWeapons[RandomNumber.Instance.Next(driverWeapons.Length)], 5000, true); + p.WarpIntoVehicle(vehicle, -1); + } + else + { + p.Inventory.GiveNewWeapon(paxWeapons[RandomNumber.Instance.Next(paxWeapons.Length)], 5000, true); + p.WarpIntoVehicle(vehicle, i - 1); + } + var b = p.AttachBlip(); + b.Scale = 0.75f; + b.Color = Color.Red; + + suspects.Add(p, b); + if (suspects.ElementAt(0).Value && suspects.ElementAt(0).Value.IsValid()) suspects.ElementAt(0).Value.EnableRoute(Color.Red); + } + } + go = true; + } + catch (Exception e) + { + Logger.ErrorCode("Found Dangerous Person", 50); + Logger.Error(e.ToString()); + this.End(); + } + + return base.OnCalloutAccepted(); + } + + public override void Process() + { + GameFiber.StartNew(() => + { + try + { + GameFiber.Yield(); + if (go && !PursuitBegan && Game.LocalPlayer.Character.Position.DistanceTo(suspects.ElementAt(0).Key) < 30f) + { + suspects.ElementAt(0).Value.EnableRoute(Color.Red); + switch (sno) + { + default: + case 0: + pursuit = Functions.CreatePursuit(); + if (pursuit is not null) + { + foreach (var p in suspects.Keys) if (p && p.IsValid()) Functions.AddPedToPursuit(pursuit, p); + foreach (var b in suspects.Values) if (b && b.IsValid()) b.Delete(); + Functions.SetPursuitIsActiveForPlayer(pursuit, true); + } + PursuitBegan = true; + break; + case 1: + new RelationshipGroup("SUSPECTS"); + new RelationshipGroup("COP"); + Game.SetRelationshipBetweenRelationshipGroups("SUSPECTS", "COP", Relationship.Hate); + Game.LocalPlayer.Character.RelationshipGroup = "COP"; + foreach (var p in suspects.Keys) + { + p.RelationshipGroup = "SUSPECTS"; + p.Tasks.FightAgainstClosestHatedTarget(5000f); + } + PursuitBegan = true; + break; + } + } + } + catch (Exception e) + { + Logger.ErrorCode("Found Dangerous Person", 60); + Logger.Error(e.ToString()); + this.End(); + } + }); + if (Game.LocalPlayer.Character.IsDead || PedExtensions.EveryoneAreDeadOrArrested(suspects.Keys.ToList())) End(); + base.Process(); + } + + public override void End() + { + Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), TranslateKey()); + foreach (var p in suspects.Keys) if (p && p.IsValid()) p.Dismiss(); + foreach (var b in suspects.Values) if (b && b.IsValid()) b.Delete(); + if (vehicle && vehicle.IsValid()) vehicle.Dismiss(); + if (pursuit is not null) Functions.ForceEndPursuit(pursuit); + base.End(); + } + + private void CheckAndDeleteBlip(bool CheckPed = false) + { + switch (CheckPed) + { + case true: + foreach (var b in suspects) if (b.Value && b.Value.IsValid() && b.Key.IsDeadOrArrested()) b.Value.Delete(); + break; + case false: + foreach (var b in suspects) if (b.Value && b.Value.IsValid()) b.Value.Delete(); + break; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/FoundDangerousPerson/SuspectData.cs b/DynamicLSPDFR/Callouts/FoundDangerousPerson/SuspectData.cs new file mode 100644 index 0000000..d18bdb6 --- /dev/null +++ b/DynamicLSPDFR/Callouts/FoundDangerousPerson/SuspectData.cs @@ -0,0 +1,23 @@ +namespace DynamicLSPDFR.Callouts; + +internal static class FoundDangerousPersonData +{ + internal enum Team : int + { + Michael, + Franklin, + Trevor, + Lester, + Everyone, + None, + } + + internal static Dictionary)> Data = new() + { + { Team.Michael, ("TAILGATER", new() { "player_zero" } ) }, + { Team.Franklin, ("BUFFALO", new() { "player_one" } ) }, + { Team.Trevor, ("BODHI2", new() { "player_two", "ig_nervousron", "ig_wade" } ) }, + { Team.Lester, ("TAILGATER", new() { "ig_lestercrest" } ) }, + { Team.Everyone, ("TAILGATER", new() { "player_zero", "ig_lestercrest", "player_two", "player_one" } ) }, + }; +} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/GangShootout/GangShootout.cs b/DynamicLSPDFR/Callouts/GangShootout/GangShootout.cs index 1d80e62..6dc9190 100644 --- a/DynamicLSPDFR/Callouts/GangShootout/GangShootout.cs +++ b/DynamicLSPDFR/Callouts/GangShootout/GangShootout.cs @@ -3,7 +3,8 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("GangShootout", CalloutProbability.Low)] internal class GangShootout : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(GangShootout)]; + internal override bool IsEnable() => ClientSettings.GangShootoutIsEnabled; + internal override string TranslateKey() => "GangShootout"; private static Vector3 SpawnPoint = GangShootoutLocations.AllLocations[LocationExtensions.GetNearestPosition(GangShootoutLocations.AllLocations)]; private static Vector3 GangSpawnPoint1; private static Vector3 GangSpawnPoint2; @@ -17,7 +18,7 @@ internal class GangShootout : CalloutBase public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 120f); Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_SHOOT_OUT_01 UNITS_RESPOND_CODE_99_01 IN_OR_ON_POSITION", SpawnPoint); @@ -32,7 +33,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Gang Shootout\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("GangShootoutDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("GangShootoutDesc"), Translation.GetString(TranslateKey())); try { @@ -191,8 +192,79 @@ public override void Process() new RelationshipGroup("GANG_TEAM2"); Game.SetRelationshipBetweenRelationshipGroups("GANG_TEAM1", "GANG_TEAM2", Relationship.Hate); Game.SetRelationshipBetweenRelationshipGroups("GANG_TEAM2", "GANG_TEAM1", Relationship.Hate); - PedExtensions.SetTeamAndFight("GANG_TEAM1", GangTeam1A, GangTeam1B, GangTeam1C, GangTeam1D, GangTeam1E, GangTeam1F, GangTeam1G); - PedExtensions.SetTeamAndFight("GANG_TEAM2", GangTeam2A, GangTeam2B, GangTeam2C, GangTeam2D, GangTeam2E, GangTeam2F, GangTeam2G); + + if (GangTeam1A && GangTeam1A.IsValid()) + { + GangTeam1A.RelationshipGroup = "GANG_TEAM1"; + GangTeam1A.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1B && GangTeam1B.IsValid()) + { + GangTeam1B.RelationshipGroup = "GANG_TEAM1"; + GangTeam1B.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1C && GangTeam1C.IsValid()) + { + GangTeam1C.RelationshipGroup = "GANG_TEAM1"; + GangTeam1C.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1D && GangTeam1D.IsValid()) + { + GangTeam1D.RelationshipGroup = "GANG_TEAM1"; + GangTeam1D.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1E && GangTeam1E.IsValid()) + { + GangTeam1E.RelationshipGroup = "GANG_TEAM1"; + GangTeam1E.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1F && GangTeam1F.IsValid()) + { + GangTeam1F.RelationshipGroup = "GANG_TEAM1"; + GangTeam1F.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1G && GangTeam1G.IsValid()) + { + GangTeam1G.RelationshipGroup = "GANG_TEAM1"; + GangTeam1G.Tasks.FightAgainstClosestHatedTarget(5000f); + } + + if (GangTeam2A && GangTeam2A.IsValid()) + { + GangTeam2A.RelationshipGroup = "GANG_TEAM2"; + GangTeam2A.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam2B && GangTeam2B.IsValid()) + { + GangTeam2B.RelationshipGroup = "GANG_TEAM2"; + GangTeam2B.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam2C && GangTeam2C.IsValid()) + { + GangTeam2C.RelationshipGroup = "GANG_TEAM2"; + GangTeam2C.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1D && GangTeam2D.IsValid()) + { + GangTeam2D.RelationshipGroup = "GANG_TEAM2"; + GangTeam2D.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam1E && GangTeam2E.IsValid()) + { + GangTeam2E.RelationshipGroup = "GANG_TEAM2"; + GangTeam2E.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam2F && GangTeam2F.IsValid()) + { + GangTeam2F.RelationshipGroup = "GANG_TEAM2"; + GangTeam2F.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (GangTeam2G && GangTeam2G.IsValid()) + { + GangTeam2G.RelationshipGroup = "GANG_TEAM2"; + GangTeam2G.Tasks.FightAgainstClosestHatedTarget(5000f); + } + HasBeginFighting = true; GameFiber.Sleep(5000); @@ -214,7 +286,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); CheckAndDePed(); CheckAndDeleteBlip(); base.End(); diff --git a/DynamicLSPDFR/Callouts/HitAndRun/HitAndRun.cs b/DynamicLSPDFR/Callouts/HitAndRun/HitAndRun.cs new file mode 100644 index 0000000..f009e8e --- /dev/null +++ b/DynamicLSPDFR/Callouts/HitAndRun/HitAndRun.cs @@ -0,0 +1,314 @@ +namespace DynamicLSPDFR.Callouts; + +[CalloutInfo("HitAndRun", CalloutProbability.Medium)] +internal class HitAndRun : CalloutBase +{ + internal override bool IsEnable() => ClientSettings.HitAndRunIsEnabled; + internal override string TranslateKey() => "HitAndRun"; + + private enum Status : int + { + Accepted, + Arrived, + Searching, + Pursuit, + } + + private Ped victim, caller, suspect; + private Vehicle suspectV; + private Blip victimAreaB, victimB, callerB, suspectB; + private LHandle pursuit; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(RandomNumber.Instance.Next(500, 750))); + private Status status = Status.Accepted; + private bool blipAttached = false; + + private List<(string, string)> conversations = new() + { + (Translation.GetString("Officer"), Translation.GetString("HitAndRunTalk1")), + (Translation.GetString("Caller"), Translation.GetString("HitAndRunTalk2")), + (Translation.GetString("Officer"), Translation.GetString("HitAndRunTalk3")), + (Translation.GetString("Caller"), Translation.GetString("HitAndRunTalk4")), + (Translation.GetString("Officer"), Translation.GetString("HitAndRunTalk5")), + }; + + public override bool OnBeforeCalloutDisplayed() + { + CalloutMessage = Translation.GetString(TranslateKey()); + CalloutPosition = SpawnPoint; + ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 30f); + Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_HIT_AND_RUN IN_OR_ON_POSITION UNITS_RESPOND_CODE_03", SpawnPoint); + return base.OnBeforeCalloutDisplayed(); + } + + public override bool OnCalloutAccepted() + { + Logger.Info("[DynamicLSPDFR] Callout \"Hit And Run\" was started."); + + MessageExtensions.SendDispatchMessage(Translation.GetString("HitAndRunDesc"), Translation.GetString(TranslateKey())); + + try + { + victim = new(SpawnPoint); + caller = new(SpawnPoint.Around2D(2f)); + if (victim && victim.IsValid()) + { + victim.IsPersistent = true; + victim.BlockPermanentEvents = true; + victim.Kill(); + } + if (caller && caller.IsValid()) + { + caller.IsPersistent = true; + caller.BlockPermanentEvents = true; + caller.Face(victim.Position); + } + } + catch (Exception e) + { + Logger.ErrorCode("Hit And Run", 51); + Logger.Error(e.ToString()); + this.End(); + } + + try + { + suspectV = new(x => x.IsCar, World.GetNextPositionOnStreet(SpawnPoint.Around(RandomNumber.Instance.Next(500, 800)))); + if (suspectV && suspectV.IsValid()) + { + suspectV.IsPersistent = true; + NativeExtensions.Drive(suspectV, 20f); + + suspect = suspectV.CreateRandomDriver(); + if (suspect && suspect.IsValid()) + { + suspect.IsPersistent = true; + suspect.BlockPermanentEvents = true; + suspect.KeepTasks = true; + suspect.Tasks.CruiseWithVehicle(30f, VehicleDrivingFlags.FollowTraffic | VehicleDrivingFlags.YieldToCrossingPedestrians | VehicleDrivingFlags.RespectIntersections); + } + } + } + catch (Exception e) + { + Logger.ErrorCode("Hit And Run", 52); + Logger.Error(e.ToString()); + this.End(); + } + + try + { + victimAreaB = new(SpawnPoint.Around(RandomNumber.Instance.Next(2, 10)), 80f); + if (victimAreaB && victimAreaB.IsValid()) + { + victimAreaB.Alpha = 0.5f; + victimAreaB.Color = Color.Yellow; + victimAreaB.Name = Translation.GetString("SearchArea"); + victimAreaB.EnableRoute(Color.Yellow); + } + } + catch (Exception e) + { + Logger.ErrorCode("Hit And Run", 53); + Logger.Error(e.ToString()); + this.End(); + } + + GameFiber.StartNew(this.Running, "[DynamicLSPDFR] Hit And Run"); + + GameFiber.StartNew(() => + { + while (true) + { + GameFiber.Yield(); + if (status is Status.Searching) + { + if (suspectB && suspectB.IsValid() && suspect && suspect.IsValid()) + { + MessageExtensions.SendDispatchMessage(string.Format(Translation.GetString("SuspectLocation"), Functions.GetZoneAtPosition(suspect.Position).RealAreaName, Translation.GetString(HeadingExtensions.GetPedDirection(suspect).ToString())), ""); + suspectB.Position = suspect.Position.Around(0f, 50f); + Functions.PlayScannerAudioUsingPosition("SUSPECT_LAST_SEEN IN_OR_ON_POSITION", suspect.Position); + } + } + GameFiber.Wait(18000); + } + }, "[DynamicLSPDFR] Hit And Run Area Update"); + + return base.OnCalloutAccepted(); + } + + private void Running() + { + while (status is Status.Accepted) + { + GameFiber.Yield(); + if (Game.LocalPlayer.Character.Position.DistanceTo(caller) < 15f) + { + Game.DisplayHelp(Translation.GetString("TalkToCaller"), true); + status = Status.Arrived; + } + } + + while (status is Status.Arrived) + { + try + { + if (victimAreaB && victimAreaB.IsValid()) victimAreaB.Delete(); + + if (!blipAttached) + { + victimB = victim.AttachBlip(); + if (victimB && victimB.IsValid()) + { + victimB.Color = Color.Red; + victimB.Scale = 0.75f; + victimB.Alpha = 1f; + victimB.Name = Translation.GetString("Victim"); + } + + callerB = caller.AttachBlip(); + if (callerB && callerB.IsValid()) + { + callerB.Color = Color.Green; + callerB.Scale = 0.75f; + callerB.Name = Translation.GetString("Caller"); + } + blipAttached = true; + } + } + catch (Exception e) + { + Logger.ErrorCode("Hit And Run", 53); + Logger.Error(e.ToString()); + this.End(); + } + + try + { + GameFiber.Yield(); + if (Vector3.Distance(Game.LocalPlayer.Character.Position, caller.Position) < 5f) + { + Game.DisplayHelp($"Press ~{Keys.Y.GetInstructionalId()}~ to talk."); + if (KeyExtensions.IsKeysDown(Keys.Y)) + { + if (caller && caller.IsValid()) caller.Tasks.ClearImmediately(); + break; + } + } + else Game.HideHelp(); + } + catch (Exception e) + { + Logger.ErrorCode("Hit And Run", 60); + Logger.Error(e.ToString()); + this.End(); + } + } + DialogExtensions.Dialog(conversations, caller); + + if (victim && victim.IsValid()) victim.Dismiss(); + if (caller && caller.IsValid()) caller.Dismiss(); + if (callerB && callerB.IsValid()) callerB.Delete(); + if (suspectB && suspectB.IsValid()) suspectB.Delete(); + MessageExtensions.SendDispatchMessage(Translation.GetString("SuspectReport"), ""); + GameFiber.Wait(5000); + MessageExtensions.SendDispatchMessage(Translation.GetString("SuspectSearching"), ""); + GameFiber.Wait(12000); + Functions.PlayScannerAudioUsingPosition("SUSPECT_LAST_SEEN IN_OR_ON_POSITION", suspect.Position); + MessageExtensions.SendDispatchMessage(string.Format(Translation.GetString("SuspectLocation"), Functions.GetZoneAtPosition(suspect.Position).RealAreaName, Translation.GetString(HeadingExtensions.GetPedDirection(suspect).ToString())), ""); + suspectB = new(suspect.Position.Around(0f, 100f), 150f); + if (suspectB && suspectB) + { + suspectB.Alpha = 0.5f; + suspectB.Color = Color.Red; + suspectB.Name = Translation.GetString("SuspectArea"); + suspectB.EnableRoute(Color.Red); + } + status = Status.Searching; + } + + public override void OnCalloutNotAccepted() + { + if (victim && victim.IsValid()) victim.Delete(); + if (caller && caller.IsValid()) caller.Delete(); + if (suspect && suspect.IsValid()) suspect.Delete(); + if (suspectV && suspectV.IsValid()) suspectV.Delete(); + if (victimB && victimB.IsValid()) victimB.Delete(); + if (victimAreaB && victimAreaB.IsValid()) victimAreaB.Delete(); + if (callerB && callerB.IsValid()) callerB.Delete(); + if (suspectB && suspectB.IsValid()) suspectB.Delete(); + base.OnCalloutNotAccepted(); + } + + public override void Process() + { + GameFiber.StartNew(() => + { + if (status is Status.Searching) + { + if (suspect.DistanceTo(Game.LocalPlayer.Character.Position) < 50f) + { + if (suspectB && suspectB.IsValid()) + { + suspectB.Delete(); + suspectB = suspect.AttachBlip(); + suspectB.IsFriendly = false; + } + + if (suspect.DistanceTo(Game.LocalPlayer.Character.Position) < 15f) + { + if (suspectB && suspectB.IsValid()) suspectB.Delete(); + pursuit = Functions.CreatePursuit(); + if (suspect && suspect.IsValid()) + { + Functions.AddPedToPursuit(pursuit, suspect); + Functions.SetPursuitIsActiveForPlayer(pursuit, true); + } + status = Status.Pursuit; + } + } + } + if (CompleteEndCondition()) End(); + CheckAndDeleteBlip(true); + }, "[DynamicLSPDFR] Hit And Run"); + base.Process(); + } + + public override void End() + { + Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); + if (victim && victim.IsValid()) victim.Dismiss(); + if (caller && caller.IsValid()) caller.Dismiss(); + if (suspect && suspect.IsValid()) suspect.Dismiss(); + if (suspectV && suspectV.IsValid()) suspectV.Dismiss(); + if (victimB && victimB.IsValid()) victimB.Delete(); + if (victimAreaB && victimAreaB.IsValid()) victimAreaB.Delete(); + if (callerB && callerB.IsValid()) callerB.Delete(); + if (suspectB && suspectB.IsValid()) suspectB.Delete(); + + base.End(); + } + + private bool CompleteEndCondition() + { + if (Game.LocalPlayer.Character.IsDead || PedExtensions.EveryoneAreDeadOrArrested(suspect)) return true; + return false; + } + + private void CheckAndDeleteBlip(bool CheckPed = false) + { + switch (CheckPed) + { + case true: + if (victimB && victimB.IsValid() && (victim.IsDeadOrArrested())) victimB.Delete(); + if (callerB && callerB.IsValid() && (caller.IsDeadOrArrested())) callerB.Delete(); + if (suspectB && suspectB.IsValid() && (suspect.IsDeadOrArrested())) suspectB.Delete(); + break; + case false: + if (victimB && victimB.IsValid()) victimB.Delete(); + if (callerB && callerB.IsValid()) callerB.Delete(); + if (suspectB && suspectB.IsValid()) suspectB.Delete(); + break; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/Investigation/SushiTerorithm.cs b/DynamicLSPDFR/Callouts/Investigation/SushiTerorithm.cs index 8f2b362..25be7bc 100644 --- a/DynamicLSPDFR/Callouts/Investigation/SushiTerorithm.cs +++ b/DynamicLSPDFR/Callouts/Investigation/SushiTerorithm.cs @@ -3,7 +3,9 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("SushiTerrorism", CalloutProbability.Low)] internal class SushiTerrorism : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(SushiTerrorism)]; + internal override bool IsEnable() => ClientSettings.SushiIsEnabled; + internal override string TranslateKey() => "SushiTerrorism"; + private (Vector3, float) SuspectPos; private int n = RandomNumber.Instance.Next(0, 2); private static Ped suspect, owner, cop1, cop2, cop3, cop4; @@ -35,7 +37,7 @@ public override bool OnBeforeCalloutDisplayed() { // n = LocationExtensions.GetNearestPositionFromNum(suspectPoint, 2)[RandomNumber.Instance.Next(2)]; SuspectPos = SushiTerrorismLocations.SuspectPoint[n]; - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SuspectPos.Item1; ShowCalloutAreaBlipBeforeAccepting(SuspectPos.Item1, 50f); Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_ACCIDENT_01 IN_OR_ON_POSITION", SuspectPos.Item1); @@ -46,7 +48,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Sushi Terrorism\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("SushiTerrorismDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("SushiTerrorismDesc"), Translation.GetString(TranslateKey())); try { @@ -380,7 +382,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); CalloutRunning = false; if (cop1 && cop1.IsValid()) cop1.Tasks.EnterVehicle(copV1, -1); diff --git a/DynamicLSPDFR/Callouts/Not Completed/Murder.cs b/DynamicLSPDFR/Callouts/Not Completed/Murder.cs index a797dec..65917e8 100644 --- a/DynamicLSPDFR/Callouts/Not Completed/Murder.cs +++ b/DynamicLSPDFR/Callouts/Not Completed/Murder.cs @@ -9,7 +9,7 @@ // private Ped murder, victim, cop1, cop2, cop3, cop4, cop5, cop6, cop7, cop8; // private Vehicle copV1, copV2, copV3, copV4; -// private Rage.Object clipBoard; +// private Object clipBoard; // private enum Location // { diff --git a/DynamicLSPDFR/Callouts/PanicButton/PanicButton.cs b/DynamicLSPDFR/Callouts/Not Completed/PanicButton/PanicButton.cs similarity index 100% rename from DynamicLSPDFR/Callouts/PanicButton/PanicButton.cs rename to DynamicLSPDFR/Callouts/Not Completed/PanicButton/PanicButton.cs diff --git a/DynamicLSPDFR/Callouts/TrafficStopBackup/Locations.cs b/DynamicLSPDFR/Callouts/Not Completed/TrafficStopBackup/Locations.cs similarity index 100% rename from DynamicLSPDFR/Callouts/TrafficStopBackup/Locations.cs rename to DynamicLSPDFR/Callouts/Not Completed/TrafficStopBackup/Locations.cs diff --git a/DynamicLSPDFR/Callouts/TrafficStopBackup/TrafficStopBackup.cs b/DynamicLSPDFR/Callouts/Not Completed/TrafficStopBackup/TrafficStopBackup.cs similarity index 100% rename from DynamicLSPDFR/Callouts/TrafficStopBackup/TrafficStopBackup.cs rename to DynamicLSPDFR/Callouts/Not Completed/TrafficStopBackup/TrafficStopBackup.cs diff --git a/DynamicLSPDFR/Callouts/Pursuit/DynamicPursuit.cs b/DynamicLSPDFR/Callouts/Pursuit/DynamicPursuit.cs index 98a8125..01c4102 100644 --- a/DynamicLSPDFR/Callouts/Pursuit/DynamicPursuit.cs +++ b/DynamicLSPDFR/Callouts/Pursuit/DynamicPursuit.cs @@ -3,16 +3,17 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("DynamicPursuit", CalloutProbability.High)] internal class DynamicPursuit : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(DynamicPursuit)]; - private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(250, 501)); + internal override bool IsEnable() => ClientSettings.DynamicPursuitIsEnabled; + internal override string TranslateKey() => "DynamicPursuit"; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(250, 501)); private Vehicle vehicle; private Ped suspect; private LHandle pursuit; public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 70f); Functions.PlayScannerAudioUsingPosition("WE_HAVE CRIME_GRAND_THEFT_AUTO IN_OR_ON_POSITION", SpawnPoint); @@ -23,7 +24,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Dynamic Pursuit\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("DynamicPursuitDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("DynamicPursuitDesc"), Translation.GetString(TranslateKey())); try { @@ -67,7 +68,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); if (suspect) suspect.Dismiss(); if (vehicle) vehicle.Dismiss(); if (pursuit is not null) Functions.ForceEndPursuit(pursuit); diff --git a/DynamicLSPDFR/Callouts/Pursuit/StolenCarPursuit.cs b/DynamicLSPDFR/Callouts/Pursuit/StolenCarPursuit.cs index 2e5127c..806f83f 100644 --- a/DynamicLSPDFR/Callouts/Pursuit/StolenCarPursuit.cs +++ b/DynamicLSPDFR/Callouts/Pursuit/StolenCarPursuit.cs @@ -3,16 +3,17 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("StolenCarPursuit", CalloutProbability.Medium)] internal class StolenCarPursuit : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(StolenCarPursuit)]; - private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(300f)); + internal override bool IsEnable() => ClientSettings.StolenCarPursuitIsEnabled; + internal override string TranslateKey() => "StolenCarPursuit"; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(300f)); private Ped suspect; private Vehicle stolenCar; private LHandle pursuit; public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 30f); Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_STOLEN_VEHICLE_01 IN_OR_ON_POSITION", SpawnPoint); @@ -32,7 +33,7 @@ public override bool OnCalloutAccepted() stolenCar.IsStolen = true; suspect = stolenCar.CreateRandomDriver(); - MessageExtensions.SendDispatchMessage(string.Format(Translation.GetString("StolenCarPursuitDesc"), stolenCar.Model.Name, stolenCar.LicensePlate), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(string.Format(Translation.GetString("StolenCarPursuitDesc"), stolenCar.Model.Name, stolenCar.LicensePlate), Translation.GetString(TranslateKey())); } if (suspect && suspect.IsValid()) { @@ -67,7 +68,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); if (suspect) suspect.Dismiss(); if (stolenCar) stolenCar.Dismiss(); if (pursuit is not null) Functions.ForceEndPursuit(pursuit); diff --git a/DynamicLSPDFR/Callouts/Pursuit/StolenMoneyTruck.cs b/DynamicLSPDFR/Callouts/Pursuit/StolenMoneyTruck.cs index d3d8c4a..5ffe02e 100644 --- a/DynamicLSPDFR/Callouts/Pursuit/StolenMoneyTruck.cs +++ b/DynamicLSPDFR/Callouts/Pursuit/StolenMoneyTruck.cs @@ -3,7 +3,9 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("StolenMoneyTruck", CalloutProbability.Low)] internal class StolenMoneyTruck : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(StolenMoneyTruck)]; + internal override bool IsEnable() => ClientSettings.StolenMoneyTruckIsEnabled; + internal override string TranslateKey() => "StolenMoneyTruck"; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(250f)); private Ped suspect, suspect2; private Vehicle moneyTruck; @@ -11,10 +13,10 @@ internal class StolenMoneyTruck : CalloutBase public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 50f); - Functions.PlayScannerAudioUsingPosition("ATTENTION_ALL_UNITS WE_HAVE DL_CRIME_STOLEN_VEHICLE_01 IN_OR_ON_POSITION IN_OR_ON_POSITION UNITS_RESPOND_CODE_99", SpawnPoint); + Functions.PlayScannerAudioUsingPosition("ATTENTION_ALL_UNITS WE_HAVE DL_CRIME_STOLEN_VEHICLE_01 IN_OR_ON_POSITION UNITS_RESPOND_CODE_99", SpawnPoint); return base.OnBeforeCalloutDisplayed(); } @@ -22,7 +24,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Stolen Money Truck\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("StolenMoneyTruckDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("StolenMoneyTruckDesc"), Translation.GetString(TranslateKey())); try { @@ -78,7 +80,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); if (suspect) suspect.Dismiss(); if (suspect2) suspect2.Dismiss(); if (moneyTruck) moneyTruck.Dismiss(); diff --git a/DynamicLSPDFR/Callouts/Robbery/Bank/BankRobbery.cs b/DynamicLSPDFR/Callouts/Robbery/Bank/BankRobbery.cs new file mode 100644 index 0000000..3dfb64f --- /dev/null +++ b/DynamicLSPDFR/Callouts/Robbery/Bank/BankRobbery.cs @@ -0,0 +1,285 @@ +namespace DynamicLSPDFR.Callouts; + +[CalloutInfo("BankRobbery", CalloutProbability.Low)] +internal class BankRobbery : CalloutBase +{ + internal override bool IsEnable() => ClientSettings.BankRobberyIsEnabled; + internal override string TranslateKey() => "BankRobbery"; + + private Ped Robber1, Robber2, Robber3, Robber4, Robber5; + private Blip Bank, Robber1B, Robber2B, Robber3B, Robber4B, Robber5B; + private Vehicle robV; + private static BankRobberyLocations.Locations loc = LocationExtensions.GetNearestPosition(BankRobberyLocations.SpawnPoints); + private Vector3 SpawnPoint = BankRobberyLocations.SpawnPoints[loc]; + private bool Arrived = false; + private WeaponHash[] Weapons = new[] { WeaponHash.CarbineRifle, WeaponHash.AssaultRifle, WeaponHash.AdvancedRifle, WeaponHash.AssaultSMG, WeaponHash.Smg }; + private string[] RobberVehicles = new[] { "baller", "baller2", "boxville2", "burrito3", "burrito4", "burrito5", "pony", "pony2", "rancherxl", "rumpo", "rumpo2", "rocoto", "seminole", "speedo", "minivan" }; + + public override bool OnBeforeCalloutDisplayed() + { + CalloutMessage = Translation.GetString(TranslateKey()); + CalloutPosition = SpawnPoint; + ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 50f); + Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_BANK_ROBBERY IN_OR_ON_POSITION UNITS_RESPOND_CODE_99", SpawnPoint); + return base.OnBeforeCalloutDisplayed(); + } + + public override bool OnCalloutAccepted() + { + Logger.Info("[DynamicLSPDFR] Callout \"Bank Robbery\" was started."); + + MessageExtensions.SendDispatchMessage(Translation.GetString("BankRobberyDesc"), Translation.GetString(TranslateKey())); + + try + { + Robber1 = new("g_m_m_chicold_01", BankRobberyLocations.Robbery1[loc], 0f); + Robber2 = new("g_m_m_chicold_01", BankRobberyLocations.Robbery2[loc], 0f); + Robber3 = new("g_m_m_chicold_01", BankRobberyLocations.Robbery3[loc], 0f); + Robber4 = new("g_m_m_chicold_01", BankRobberyLocations.Robbery4[loc], 0f); + Robber5 = new("g_m_m_chicold_01", BankRobberyLocations.Robbery5[loc], 0f); + if (Robber1 && Robber1.IsValid()) + { + Robber1.IsPersistent = true; + Robber1.BlockPermanentEvents = true; + Robber1.MaxHealth = 500; + Robber1.Health = 500; + Robber1.Armor = 500; + Robber1.SetPedSuffersCriticalHits(false); + Robber1.Inventory.GiveNewWeapon(Weapons[RandomNumber.Instance.Next(Weapons.Length)], 5000, true); + Robber1B = Robber1.AttachBlip(); + if (Robber1B && Robber1B.IsValid()) + { + Robber1B.IsFriendly = false; + Robber1B.Scale = 0.75f; + Robber1B.Name = Translation.GetString("Robber"); + } + } + if (Robber2 && Robber2.IsValid()) + { + Robber2.IsPersistent = true; + Robber2.BlockPermanentEvents = true; + Robber2.MaxHealth = 500; + Robber2.Health = 500; + Robber2.Armor = 500; + Robber2.SetPedSuffersCriticalHits(false); + Robber2.Inventory.GiveNewWeapon(Weapons[RandomNumber.Instance.Next(Weapons.Length)], 5000, true); + Robber2B = Robber2.AttachBlip(); + if (Robber2B && Robber2B.IsValid()) + { + Robber2B.IsFriendly = false; + Robber2B.Scale = 0.75f; + Robber2B.Name = Translation.GetString("Robber"); + } + } + if (Robber3 && Robber3.IsValid()) + { + Robber3.IsPersistent = true; + Robber3.BlockPermanentEvents = true; + Robber3.MaxHealth = 500; + Robber3.Health = 500; + Robber3.Armor = 700; + Robber3.SetPedSuffersCriticalHits(false); + Robber3.Inventory.GiveNewWeapon(Weapons[RandomNumber.Instance.Next(Weapons.Length)], 5000, true); + Robber3B = Robber3.AttachBlip(); + if (Robber3B && Robber3B.IsValid()) + { + Robber3B.IsFriendly = false; + Robber3B.Scale = 0.75f; + Robber3B.Name = Translation.GetString("Robber"); + } + } + if (Robber4 && Robber4.IsValid()) + { + Robber4.IsPersistent = true; + Robber4.BlockPermanentEvents = true; + Robber4.MaxHealth = 500; + Robber4.Health = 500; + Robber4.Armor = 800; + Robber4.SetPedSuffersCriticalHits(false); + Robber4.Inventory.GiveNewWeapon(Weapons[RandomNumber.Instance.Next(Weapons.Length)], 5000, true); + Robber4B = Robber4.AttachBlip(); + if (Robber4B && Robber4B.IsValid()) + { + Robber4B.IsFriendly = false; + Robber4B.Scale = 0.75f; + Robber4B.Name = Translation.GetString("Robber"); + } + } + if (Robber5 && Robber5.IsValid()) + { + Robber5.IsPersistent = true; + Robber5.BlockPermanentEvents = true; + Robber5.MaxHealth = 500; + Robber5.Health = 500; + Robber5.Armor = 1000; + Robber5.SetPedSuffersCriticalHits(false); + Robber5.Inventory.GiveNewWeapon(Weapons[RandomNumber.Instance.Next(Weapons.Length)], 5000, true); + Robber5B = Robber5.AttachBlip(); + if (Robber5B && Robber5B.IsValid()) + { + Robber5B.IsFriendly = false; + Robber5B.Scale = 0.75f; + Robber5B.Name = Translation.GetString("Robber"); + } + } + } + catch (Exception e) + { + Logger.ErrorCode("Bank Robbery", 51); + Logger.Error(e.ToString()); + this.End(); + } + + try + { + robV = new(RobberVehicles[RandomNumber.Instance.Next(RobberVehicles.Length)], BankRobberyLocations.RobberVehicle[loc].Item1, BankRobberyLocations.RobberVehicle[loc].Item2); + if (robV && robV.IsValid()) + { + robV.IsSirenOn = true; + robV.IsSirenSilent = true; + robV.IsPersistent = true; + if (RandomNumber.Instance.Next(2) is 0) robV.IsStolen = true; + if (Main.Language is Languages.Japanese) robV.LicensePlate = "114514"; + } + } + catch (Exception e) + { + Logger.ErrorCode("Bank Robbery", 52); + Logger.Error(e.ToString()); + this.End(); + } + + try + { + Bank = new(SpawnPoint, 90f); + if (Bank && Bank.IsValid()) + { + Bank.Alpha = 0.5f; + Bank.Color = Color.Red; + Bank.Name = Translation.GetString("RobbedBank"); + Bank.EnableRoute(Color.Red); + } + } + catch (Exception e) + { + Logger.ErrorCode("Bank Robbery", 53); + Logger.Error(e.ToString()); + this.End(); + } + + return base.OnCalloutAccepted(); + } + + public override void OnCalloutNotAccepted() + { + if (Robber1 && Robber1.IsValid()) Robber1.Delete(); + if (Robber2 && Robber2.IsValid()) Robber2.Delete(); + if (Robber3 && Robber3.IsValid()) Robber3.Delete(); + if (Robber4 && Robber4.IsValid()) Robber4.Delete(); + if (Robber5 && Robber5.IsValid()) Robber5.Delete(); + if (Bank && Bank.IsValid()) Bank.Delete(); + if (Robber1B && Robber1B.IsValid()) Robber1B.Delete(); + if (Robber2B && Robber2B.IsValid()) Robber2B.Delete(); + if (Robber3B && Robber3B.IsValid()) Robber3B.Delete(); + if (Robber4B && Robber4B.IsValid()) Robber4B.Delete(); + if (Robber5B && Robber5B.IsValid()) Robber5B.Delete(); + base.OnCalloutNotAccepted(); + } + + public override void Process() + { + GameFiber.StartNew(() => + { + if (robV.DistanceTo(Game.LocalPlayer.Character.Position) < 30f && !Arrived) + { + if (Bank && Bank.IsValid()) + { + Bank.DisableRoute(); + Bank.Delete(); + } + + GameFiber.Wait(3000); + new RelationshipGroup("ROBBERY"); + new RelationshipGroup("COP"); + Game.SetRelationshipBetweenRelationshipGroups("ROBBERY", "COP", Relationship.Hate); + Game.LocalPlayer.Character.RelationshipGroup = "COP"; + if (Robber1 && Robber1.IsValid()) + { + Robber1.RelationshipGroup = "ROBBERY"; + Robber1.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (Robber2 && Robber2.IsValid()) + { + Robber2.RelationshipGroup = "ROBBERY"; + Robber2.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (Robber3 && Robber3.IsValid()) + { + Robber3.RelationshipGroup = "ROBBERY"; + Robber3.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (Robber4 && Robber4.IsValid()) + { + Robber4.RelationshipGroup = "ROBBERY"; + Robber4.Tasks.FightAgainstClosestHatedTarget(5000f); + } + if (Robber5 && Robber5.IsValid()) + { + Robber5.RelationshipGroup = "ROBBERY"; + Robber5.Tasks.FightAgainstClosestHatedTarget(5000f); + } + Arrived = true; + } + if (CompleteEndCondition()) End(); + CheckAndDeleteBlip(true); + + }, "[DynamicLSPDFR] Bank Robbery"); + base.Process(); + } + + public override void End() + { + Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); + if (Robber1 && Robber1.IsValid()) Robber1.Dismiss(); + if (Robber2 && Robber2.IsValid()) Robber2.Dismiss(); + if (Robber3 && Robber3.IsValid()) Robber3.Dismiss(); + if (Robber4 && Robber4.IsValid()) Robber4.Dismiss(); + if (Robber5 && Robber5.IsValid()) Robber5.Dismiss(); + if (Bank && Bank.IsValid()) Bank.Delete(); + if (Robber1B && Robber1B.IsValid()) Robber1B.Delete(); + if (Robber2B && Robber2B.IsValid()) Robber2B.Delete(); + if (Robber3B && Robber3B.IsValid()) Robber3B.Delete(); + if (Robber4B && Robber4B.IsValid()) Robber4B.Delete(); + if (Robber5B && Robber5B.IsValid()) Robber5B.Delete(); + + base.End(); + } + + private bool CompleteEndCondition() + { + if (Game.LocalPlayer.Character.IsDead || PedExtensions.EveryoneAreDeadOrArrested(Robber1, Robber2, Robber3, Robber4, Robber5)) return true; + return false; + } + + private void CheckAndDeleteBlip(bool CheckPed = false) + { + switch (CheckPed) + { + case true: + if (Robber1B && Robber1B.IsValid() && (Robber1.IsDeadOrArrested())) Robber1B.Delete(); + if (Robber2B && Robber2B.IsValid() && (Robber2.IsDeadOrArrested())) Robber2B.Delete(); + if (Robber3B && Robber3B.IsValid() && (Robber3.IsDeadOrArrested())) Robber3B.Delete(); + if (Robber4B && Robber4B.IsValid() && (Robber4.IsDeadOrArrested())) Robber4B.Delete(); + if (Robber5B && Robber5B.IsValid() && (Robber5.IsDeadOrArrested())) Robber5B.Delete(); + break; + case false: + if (Robber1B && Robber1B.IsValid()) Robber1B.Delete(); + if (Robber2B && Robber2B.IsValid()) Robber2B.Delete(); + if (Robber3B && Robber3B.IsValid()) Robber3B.Delete(); + if (Robber4B && Robber4B.IsValid()) Robber4B.Delete(); + if (Robber5B && Robber5B.IsValid()) Robber5B.Delete(); + break; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/Robbery/Bank/Locations.cs b/DynamicLSPDFR/Callouts/Robbery/Bank/Locations.cs new file mode 100644 index 0000000..5c5a0f5 --- /dev/null +++ b/DynamicLSPDFR/Callouts/Robbery/Bank/Locations.cs @@ -0,0 +1,60 @@ +namespace DynamicLSPDFR.Callouts; + +internal static class BankRobberyLocations +{ + internal enum Locations : int + { + PillboxHill, + Burton, + Paleto, + } + + internal static Dictionary SpawnPoints = new() + { + { Locations.PillboxHill, new(146.9374f, -1044.931f, 30f) }, + { Locations.Burton, new(-353.9496f, -53.21059f, 50f) }, + { Locations.Paleto, new(-113.0431f, 6469.044f, 30f) }, + }; + + internal static Dictionary Robbery1 = new() + { + { Locations.PillboxHill, new(147.2159f, -1045.003f, 39.369f) }, + { Locations.Burton, new(-353.9496f, -53.21059f, 49.037f) }, + { Locations.Paleto, new(-113.0431f, 6469.044f, 31.627f) }, + }; + + internal static Dictionary Robbery2 = new() + { + { Locations.PillboxHill, new(145.715f, -1044.981f, 29.378f) }, + { Locations.Burton, new(-355.0357f, -54.30582f, 49.047f) }, + { Locations.Paleto, new(-101.5976f, 6463.146f, 31.627f) }, + }; + + internal static Dictionary Robbery3 = new() + { + { Locations.PillboxHill, new(144.3407f, -1043.922f, 29.368f) }, + { Locations.Burton, new(-356.4601f, -53.16462f, 49.037f) }, + { Locations.Paleto, new(-104.261f, 6471.767f, 31.627f) }, + }; + + internal static Dictionary Robbery4 = new() + { + { Locations.PillboxHill, new(142.5871f, -1043.835f, 29.368f) }, + { Locations.Burton, new(-358.6454f, -53.25273f, 49.037f) }, + { Locations.Paleto, new(-107.161f, 6474.427f, 31.627f) }, + }; + + internal static Dictionary Robbery5 = new() + { + { Locations.PillboxHill, new(144.9723f, -1036.951f, 29.369f) }, + { Locations.Burton, new(-355.4163f, -47.41251f, 49.037f) }, + { Locations.Paleto, new(-103.4466f, 6477.631f, 31.627f) }, + }; + + internal static Dictionary RobberVehicle = new() + { + { Locations.PillboxHill, (new(147.9261f, -1028.209f, 28.977f), -109.0291f) }, + { Locations.Burton, (new(-341.7926f, -30.77651f, 47.282f), -109.2123f) }, + { Locations.Paleto, (new(-115.7394f, 6457.531f, 31.216f), 44.26528f) }, + }; +} \ No newline at end of file diff --git a/DynamicLSPDFR/Callouts/Robbery/Locations.cs b/DynamicLSPDFR/Callouts/Robbery/Store/Locations.cs similarity index 100% rename from DynamicLSPDFR/Callouts/Robbery/Locations.cs rename to DynamicLSPDFR/Callouts/Robbery/Store/Locations.cs diff --git a/DynamicLSPDFR/Callouts/Robbery/StoreRobbery.cs b/DynamicLSPDFR/Callouts/Robbery/Store/StoreRobbery.cs similarity index 90% rename from DynamicLSPDFR/Callouts/Robbery/StoreRobbery.cs rename to DynamicLSPDFR/Callouts/Robbery/Store/StoreRobbery.cs index c447d26..76c5ecd 100644 --- a/DynamicLSPDFR/Callouts/Robbery/StoreRobbery.cs +++ b/DynamicLSPDFR/Callouts/Robbery/Store/StoreRobbery.cs @@ -3,7 +3,9 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("StoreRobbery", CalloutProbability.Medium)] internal class StoreRobbery : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(StoreRobbery)]; + internal override bool IsEnable() => ClientSettings.StoreRobberyIsEnabled; + internal override string TranslateKey() => "StoreRobbery"; + private Ped suspect; private Blip blip; private LHandle pursuit; @@ -13,7 +15,7 @@ internal class StoreRobbery : CalloutBase public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 50f); Functions.PlayScannerAudioUsingPosition("WE_HAVE CRIME_ROBBERY IN_OR_ON_POSITION", SpawnPoint); @@ -24,7 +26,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Store Robbery\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("StoreRobberyDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("StoreRobberyDesc"), Translation.GetString(TranslateKey())); try { @@ -99,8 +101,8 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); - if (suspect) suspect.Detach(); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); + if (suspect) suspect.Dismiss(); if (blip) blip.Delete(); base.End(); } diff --git a/DynamicLSPDFR/Callouts/StreetFight/StreetFight.cs b/DynamicLSPDFR/Callouts/StreetFight/StreetFight.cs index 8077f5c..af67af6 100644 --- a/DynamicLSPDFR/Callouts/StreetFight/StreetFight.cs +++ b/DynamicLSPDFR/Callouts/StreetFight/StreetFight.cs @@ -3,9 +3,10 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("StreetFight", CalloutProbability.Medium)] internal class StreetFight : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(StreetFight)]; - private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(80f, 500f)); + internal override bool IsEnable() => ClientSettings.StreetFightIsEnabled; + internal override string TranslateKey() => "StreetFight"; + private Vector3 SpawnPoint = World.GetNextPositionOnStreet(Game.LocalPlayer.Character.Position.Around(80f, 500f)); private Ped suspect1, suspect2; private Blip area, susB1, susB2; private LHandle pursuit; @@ -13,7 +14,7 @@ internal class StreetFight : CalloutBase public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 20f); Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_CIVIL_DISTURBANCE_01 IN_OR_ON_POSITION", SpawnPoint); @@ -24,7 +25,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Street Fight\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("StreetFightDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("StreetFightDesc"), Translation.GetString(TranslateKey())); try { @@ -83,8 +84,16 @@ public override void Process() new RelationshipGroup("CRIMINAL2"); Game.SetRelationshipBetweenRelationshipGroups("CRIMINAL1", "CRIMINAL2", Relationship.Hate); Game.SetRelationshipBetweenRelationshipGroups("CRIMINAL2", "CRIMINAL1", Relationship.Hate); - PedExtensions.SetTeamAndFight("CRIMINAL1", suspect1); - PedExtensions.SetTeamAndFight("CRIMINAL2", suspect2); + if (suspect1 && suspect1.IsValid()) + { + suspect1.RelationshipGroup = "CRIMINAL1"; + suspect1.Tasks.FightAgainstClosestHatedTarget(500f); + } + if (suspect2 && suspect2.IsValid()) + { + suspect2.RelationshipGroup = "CRIMINAL2"; + suspect2.Tasks.FightAgainstClosestHatedTarget(500f); + } susB1 = suspect1.AttachBlip(); susB2 = suspect2.AttachBlip(); @@ -143,7 +152,7 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); if (suspect1 && suspect1.IsValid()) suspect1.Dismiss(); if (suspect2 && suspect2.IsValid()) suspect2.Dismiss(); if (area && area.IsValid()) area.Delete(); diff --git a/DynamicLSPDFR/Callouts/WantedCriminalFound/WantedCriminalFound.cs b/DynamicLSPDFR/Callouts/WantedCriminalFound/WantedCriminalFound.cs index c2dfe88..62bb117 100644 --- a/DynamicLSPDFR/Callouts/WantedCriminalFound/WantedCriminalFound.cs +++ b/DynamicLSPDFR/Callouts/WantedCriminalFound/WantedCriminalFound.cs @@ -3,7 +3,9 @@ namespace DynamicLSPDFR.Callouts; [CalloutInfo("WantedCriminalFound", CalloutProbability.Medium)] internal class WantedCriminalFound : CalloutBase { - private string TranslateKey = CalloutList.AllCallouts[typeof(WantedCriminalFound)]; + internal override bool IsEnable() => ClientSettings.CriminalFoundIsEnabled; + internal override string TranslateKey() => "WantedCriminalFound"; + private Vector3 SpawnPoint = WantedCriminalFoundLocations.SpawnPoints[LocationExtensions.GetNearestPositionFromNum(WantedCriminalFoundLocations.SpawnPoints, 3)[RandomNumber.Instance.Next(3)]]; private WeaponHash[] Weapons = new[] { WeaponHash.StunGun, WeaponHash.Pistol, WeaponHash.CarbineRifle }; private Ped criminal; @@ -13,7 +15,7 @@ internal class WantedCriminalFound : CalloutBase public override bool OnBeforeCalloutDisplayed() { - CalloutMessage = Translation.GetString(TranslateKey); + CalloutMessage = Translation.GetString(TranslateKey()); CalloutPosition = SpawnPoint; ShowCalloutAreaBlipBeforeAccepting(SpawnPoint, 50f); Functions.PlayScannerAudioUsingPosition("WE_HAVE DL_CRIME_SUSPECT_RESISTING_ARREST_01 IN_OR_ON_POSITION", SpawnPoint); @@ -24,7 +26,7 @@ public override bool OnCalloutAccepted() { Logger.Info("[DynamicLSPDFR] Callout \"Wanted Criminal Found\" was started."); - MessageExtensions.SendDispatchMessage(Translation.GetString("WantedCriminalFoundDesc"), Translation.GetString(TranslateKey)); + MessageExtensions.SendDispatchMessage(Translation.GetString("WantedCriminalFoundDesc"), Translation.GetString(TranslateKey())); try { @@ -108,8 +110,8 @@ public override void Process() public override void End() { Functions.PlayScannerAudio("ATTENTION_ALL_UNITS DL_CODE4 DL_NO_FURTHER_UNITS_REQUIRED"); - MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey)); - if (criminal) criminal.Detach(); + MessageExtensions.SendDispatchMessage(Translation.GetString("Code4"), Translation.GetString(TranslateKey())); + if (criminal) criminal.Dismiss(); if (blip) blip.Delete(); base.End(); } diff --git a/DynamicLSPDFR/Common/API.cs b/DynamicLSPDFR/Common/API.cs deleted file mode 100644 index 8a2f7b0..0000000 --- a/DynamicLSPDFR/Common/API.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace DynamicLSPDFR.Common; - -internal static class API -{ - internal static bool IsPluginRunning(string name, Version version = null) => Functions.GetAllUserPlugins().Select(x => x.GetName()).Any(y => y.Name.ToLower() == name.ToLower() && (version is (Version)null || y.Version.CompareTo(version) >= 0)); -} \ No newline at end of file diff --git a/DynamicLSPDFR/Common/Backup.cs b/DynamicLSPDFR/Common/Backup.cs deleted file mode 100644 index 7c34082..0000000 --- a/DynamicLSPDFR/Common/Backup.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace DynamicLSPDFR.Common; - -internal static class BackupCommon -{ - internal static (string, string)[] CopMaleIdleAnim = new[] - { - ("amb@world_human_cop_idles@male@base", "base"), - ("amb@world_human_cop_idles@male@idle_a", "idle_a"), - ("amb@world_human_cop_idles@male@idle_a", "idle_b"), - ("amb@world_human_cop_idles@male@idle_a", "idle_c"), - ("amb@world_human_cop_idles@male@idle_b", "idle_d"), - ("amb@world_human_cop_idles@male@idle_b", "idle_e"), - }; - - internal static (string, string)[] CopFemaleIdleAnim = new[] - { - ("amb@world_human_cop_idles@female@base", "base"), - ("amb@world_human_cop_idles@female@idle_a", "idle_a"), - ("amb@world_human_cop_idles@female@idle_a", "idle_b"), - ("amb@world_human_cop_idles@female@idle_a", "idle_c"), - ("amb@world_human_cop_idles@female@idle_b", "idle_d"), - ("amb@world_human_cop_idles@female@idle_b", "idle_e"), - }; -} \ No newline at end of file diff --git a/DynamicLSPDFR/Common/Menu.cs b/DynamicLSPDFR/Common/Menu.cs deleted file mode 100644 index 704a828..0000000 --- a/DynamicLSPDFR/Common/Menu.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace DynamicLSPDFR.Common; - -internal static class MenuCommon -{ - internal static readonly string PluginInfo = new StringBuilder(RSFormat.Bold).Append(RSFormat.ColorBlue).Append("DynamicLSPDFR").Append(RSFormat.Default).Append(RSFormat.Bold).Append(" Version.").Append(RSFormat.ColorOrange).Append(Main.PLUGIN_VERSION_STRING).Append(RSFormat.Default).ToString(); -} \ No newline at end of file diff --git a/DynamicLSPDFR/DynamicLSPDFR.ini b/DynamicLSPDFR/DynamicLSPDFR.ini index cd016c4..470357e 100644 --- a/DynamicLSPDFR/DynamicLSPDFR.ini +++ b/DynamicLSPDFR/DynamicLSPDFR.ini @@ -15,6 +15,25 @@ OfficerName = Officer StationName = [Keys] -; Open Context Menu key OpenContextMenuKey = O -OpenContextMenuKey-Modifier = None \ No newline at end of file +OpenContextMenuKey-Modifier = None + +UnitsTeleportToNearbyPlayerKey = U +UnitsTeleportToNearbyPlayerKey-Modifier = LControlKey + +[Callouts] +FoundDangerousPerson = true +GangShootout = true +HitAndRun = true +SushiTerrorism = true +BankRobbery = true +StoreRobbery = true +StreetFight = true +WantedCriminalFound = true +DynamicPursuit = true +StolenCarPursuit = true +StolenMoneyTruck = true + +[UnitsSetting] +; You should set value between 80 to 300 +CoronerSpawnDistance = 120 \ No newline at end of file diff --git a/DynamicLSPDFR/Enums.cs b/DynamicLSPDFR/Enums.cs index a14a1ea..8b13cec 100644 --- a/DynamicLSPDFR/Enums.cs +++ b/DynamicLSPDFR/Enums.cs @@ -1,5 +1,117 @@ namespace DynamicLSPDFR; +internal enum CauseOfDeathHash : uint +{ + ElectricFence = 0x92BD4EBB, + WaterCannon = 0xCC34325E, + FlyingOutOfWindscreen = 0x7FC7D7, + RunOverByCar = 0xA36D413E, + Fall = 0xCDC174B0, + Animal = 0xF9FBAEBE, + AirstrikeRocket = 0x13579279, + Bleeding = 0x8B7333FB, + BarbedWire = 0x48E7B178, + Drownding = 0xFF58C4FB, + DrowndingInVehicle = 0x736F5990, + Explosion = 0x2024F4E8, + Exhaustion = 0x364A29EC, + Fire = 0xDF8E89EB, + HelicopterCrash = 0x145F1012, + + Dagger = 0x92A27487, + Bat = 0x958A4A8F, + Bottle = 0xF9E6AA4B, + Crowbar = 0x84BD7BFD, + Unarmed = 0xA2719263, + Flashlight = 0x8BB05FD7, + GolfClub = 0x440E4788, + Hammer = 0x4E875F73, + Hatchet = 0xF9DCBF2D, + Knuckle = 0xD8DF3C3C, + Knife = 0x99B507EA, + Machete = 0xDD5DF8D9, + Switchblade = 0xDFE37640, + Nightstick = 0x678B81B1, + Wrench = 0x19044EE0, + Battleaxe = 0xCD274149, + PoolCue = 0x94117305, + StoneHatchet = 0x3813FC08, + Pistol = 0x1B06D571, + Pistol_mk2 = 0xBFE256D4, + CombatPistol = 0x5EF9FEC4, + APPistol = 0x22D8FE39, + StunGun = 0x3656C8C1, + Pistol50 = 0x99AEEB3B, + SnsPistol = 0xBFD21232, + SnsPistol_mk2 = 0x88374054, + HeavyPistol = 0xD205520E, + VintagePistol = 0x83839C4, + FlareGun = 0x47757124, + MarksmanPistol = 0xDC4DB296, + Revolver = 0xC1B3C3D1, + Revolver_mk2 = 0xCB96392F, + Doubleaction = 0x97EA20B8, + RayPistol = 0xAF3696A1, + CeramicPistol = 0x2B5EF5EC, + NavyRevolver = 0x917F6C8C, + MicroSmg = 0x13532244, + Smg = 0x2BE6766B, + Smg_mk2 = 0x78A97CD0, + AssaultSmg = 0xEFE7E2DF, + CombatPdw = 0xA3D4D34, + MachinePistol = 0xDB1AA450, + MiniSmg = 0xBD248B55, + RayCarbine = 0x476BF155, + PumpShotgun = 0x1D073A89, + PumpShotgun_mk2 = 0x555AF99A, + SawnOffShotgun = 0x7846A318, + AssaultShotgun = 0xE284C527, + BullpupShotgun = 0x9D61E50F, + Musket = 0xA89CB99E, + HeavyShotgun = 0x3AABBBAA, + DbShotgun = 0xEF951FBB, + AutoShotgun = 0x12E82D3D, + AssaultRifle = 0xBFEFFF6D, + AssaultRifle_mk2 = 0x394F415C, + Carbinerifle = 0x83BF0278, + Carbinerifle_mk2 = 0xFAD1F1C9, + AdvancedRifle = 0xAF113F99, + SpecialCarbine = 0xC0A3098D, + SpecialCarbine_mk2 = 0x969C3D67, + BullpupRifle = 0x7F229F94, + BullpupRifle_mk2 = 0x84D6FAFD, + CompactRifle = 0x624FE830, + Mg = 0x9D07F764, + CombatMg = 0x7FD62962, + CombatMg_mk2 = 0xDBBD7280, + Gusenberg = 0x61012683, + SniperRifle = 0x5FC3C11, + HeavySniper = 0xC472FE2, + HeavySniper_mk2 = 0xA914799, + MarksmanRifle = 0xC734385A, + MarksmanRifle_mk2 = 0x6A6C02E0, + Rpg = 0xB1CA77B1, + GrenadeLauncher = 0xA284510B, + MiniGun = 0x42BF8A85, + Firework = 0x7F7497E5, + RailGun = 0x6D544C99, + HomingLauncher = 0x63AB0442, + CompactLauncher = 0x781FE4A, + RayMiniGun = 0xB62D1F67, + Grenade = 0x93E220BD, + BzGas = 0xA0973D5E, + SmokeGrenade = 0xFDBC8A50, + Flare = 0x497FACC3, + Molotov = 0x24B17070, + StickyBomb = 0x2C3731D9, + ProxMine = 0xAB564B93, + Snowball = 0x787F0BB, + PipeBomb = 0xBA45E8B8, + PetrolCan = 0x34A67B97, + FireExtinguisher = 0x60EC506, + HazardCan = 0xBA536372, +} + internal enum WeatherHash : uint { EXTRA_SUNNY = 0x97AA0A79, diff --git a/DynamicLSPDFR/Extensions/ConvertExtensions.cs b/DynamicLSPDFR/Extensions/ConvertExtensions.cs deleted file mode 100644 index 7631919..0000000 --- a/DynamicLSPDFR/Extensions/ConvertExtensions.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class ConvertExtensions -{ - // internal static BackupUnitWeatherType ConvertToBackupWeather(WeatherHash weather) - // { - // switch (weather) - // { - // default: - // case WeatherHash.EXTRA_SUNNY: - // case WeatherHash.CLEAR: - // case WeatherHash.NEUTRAL: - // case WeatherHash.SMOG: - // case WeatherHash.FOGGY: - // case WeatherHash.OVERCAST: - // case WeatherHash.CLOUDS: - // case WeatherHash.HALLOWEEN: - // return BackupUnitWeatherType.Sunny; - // case WeatherHash.CLEARING: - // case WeatherHash.RAIN: - // case WeatherHash.THUNDER: - // return BackupUnitWeatherType.Rainy; - // case WeatherHash.SNOW: - // case WeatherHash.SNOWLIGHT: - // case WeatherHash.BLIZZARD: - // case WeatherHash.XMAS: - // return BackupUnitWeatherType.Snowy; - // } - // } - - // internal static BackupUnitWeatherType ConvertToBackupWeather(string weather) - // { - // weather.ToUpper(); - // return weather switch - // { - // "SUNNY" => BackupUnitWeatherType.Sunny, - // "RAINY" => BackupUnitWeatherType.Rainy, - // "SNOWY" => BackupUnitWeatherType.Snowy, - // _ => BackupUnitWeatherType.Sunny, - // }; - // } - - internal static EWorldZoneCounty ConvertToWorldZoneCounty(string county) - { - county.ToUpper(); - return county switch - { - "LOSSANTOS" => EWorldZoneCounty.LosSantos, - "LOSSANTOSCOUNTY" => EWorldZoneCounty.LosSantosCounty, - "BLAINECOUNTY" => EWorldZoneCounty.BlaineCounty, - "NORTHYANKTON" => EWorldZoneCounty.NorthYankton, - _ => EWorldZoneCounty.LosSantos, - }; - } - - // internal static BackupWorldZoneCounty ConvertToBackupCounty(string county) - // { - // county.ToUpper(); - // return county switch - // { - // "LOSSANTOS" => BackupWorldZoneCounty.LosSantos, - // "LOSSANTOSCOUNTY" => BackupWorldZoneCounty.LosSantosCounty, - // "BLAINECOUNTY" => BackupWorldZoneCounty.BlaineCounty, - // "NORTHYANKTON" => BackupWorldZoneCounty.NorthYankton, - // _ => BackupWorldZoneCounty.LosSantos, - // }; - // } - - // internal static BackupWorldZoneCounty ConvertToBackupCounty(EWorldZoneCounty county) => - // county switch - // { - // EWorldZoneCounty.LosSantos => BackupWorldZoneCounty.LosSantos, - // EWorldZoneCounty.LosSantosCounty => BackupWorldZoneCounty.LosSantosCounty, - // EWorldZoneCounty.BlaineCounty => BackupWorldZoneCounty.BlaineCounty, - // EWorldZoneCounty.NorthYankton => BackupWorldZoneCounty.NorthYankton, - // _ => BackupWorldZoneCounty.LosSantos, - // }; -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/DialogExtensions.cs b/DynamicLSPDFR/Extensions/DialogExtensions.cs index fb80b35..ce9f619 100644 --- a/DynamicLSPDFR/Extensions/DialogExtensions.cs +++ b/DynamicLSPDFR/Extensions/DialogExtensions.cs @@ -18,6 +18,7 @@ internal static void Dialog(List<(string, string)> Lines, Ped target = null) sb.Append(RSFormat.Default); sb.Append(": "); if (Lines[i].Item2 is "SushiTerrorismSuspect3-1") sb.Append(string.Format(Translation.GetString(Lines[i].Item2), station, Main.OfficerName)); + else if (Lines[i].Item2 is "HitAndRunTalk4") sb.Append(string.Format(Translation.GetString(Lines[i].Item2), CalloutsCommon.LicenseNumber, CalloutsCommon.VehicleColor.ToString())); else sb.Append(Translation.GetString(Lines[i].Item2)); sb.Append(" ").Append($"({i + 1}/{Lines.Count})"); Game.DisplaySubtitle(sb.ToString(), 10000); @@ -30,7 +31,7 @@ internal static void Dialog(List<(string, string)> Lines, Ped target = null) } if (!HandlingSpeech) break; } - if (target != null) target.Tasks.ClearImmediately(); + if (target && target.IsValid()) target.Tasks.ClearImmediately(); HandlingSpeech = false; Game.HideHelp(); diff --git a/DynamicLSPDFR/Extensions/HeadingExtensions.cs b/DynamicLSPDFR/Extensions/HeadingExtensions.cs deleted file mode 100644 index 450627a..0000000 --- a/DynamicLSPDFR/Extensions/HeadingExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class HeadingExtensions -{ - internal static Directions GetPedDirection(this Ped ped) - { - if ((348.75f <= ped.Heading && ped.Heading <= 360f) || (0f <= ped.Heading && ped.Heading < 11.25f)) return Directions.N; - else if (11.25f <= ped.Heading && ped.Heading < 33.75f) return Directions.NNW; - else if (33.75f <= ped.Heading && ped.Heading < 56.25f) return Directions.NW; - else if (56.25 <= ped.Heading && ped.Heading < 78.75f) return Directions.WNW; - else if (78.75f <= ped.Heading && ped.Heading < 101.25f) return Directions.W; - else if (101.25f <= ped.Heading && ped.Heading < 123.75f) return Directions.WSW; - else if (123.75f <= ped.Heading && ped.Heading < 146.25f) return Directions.SW; - else if (146.25f <= ped.Heading && ped.Heading < 168.75f) return Directions.SSW; - else if (168.75f <= ped.Heading && ped.Heading < 191.25f) return Directions.S; - else if (191.25f <= ped.Heading && ped.Heading < 213.75f) return Directions.SSE; - else if (213.75f <= ped.Heading && ped.Heading < 236.25f) return Directions.SE; - else if (236.25f <= ped.Heading && ped.Heading < 258.75f) return Directions.ESE; - else if (258.75f <= ped.Heading && ped.Heading < 281.25f) return Directions.E; - else if (281.25f <= ped.Heading && ped.Heading < 303.75f) return Directions.ENE; - else if (303.75f <= ped.Heading && ped.Heading < 326.25f) return Directions.NE; - else if (326.25f <= ped.Heading && ped.Heading < 348.75f) return Directions.NNE; - else return Directions.Unknown; - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/KeyExtensions.cs b/DynamicLSPDFR/Extensions/KeyExtensions.cs deleted file mode 100644 index a9c47ec..0000000 --- a/DynamicLSPDFR/Extensions/KeyExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class KeyExtensions -{ - /// - /// Get key input in game. - /// - /// Main key. - /// Modifier key. If it not specified, automatically set to None. - /// Key pressed status. - internal static bool IsKeysDown(Keys Main, Keys Modifier = Keys.None) - { - return (Game.IsKeyDown(Modifier) || Modifier is Keys.None) && Game.IsKeyDown(Main); - } - - /// - /// Convert to Key from string. - /// - /// string which wants convert to key - /// Keys id - internal static Keys ConvertToKey(this string KeyString) - { - var converter = new KeysConverter(); - return (Keys)converter.ConvertFromString(KeyString); - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Localization/Translation.cs b/DynamicLSPDFR/Extensions/Localization/Translation.cs index fe7081d..f3aa856 100644 --- a/DynamicLSPDFR/Extensions/Localization/Translation.cs +++ b/DynamicLSPDFR/Extensions/Localization/Translation.cs @@ -1,31 +1,5 @@ namespace DynamicLSPDFR.Extensions.Localization; -internal enum Languages : int -{ - Japanese = 0, - Chinese_Simplified = 1, - Chinese_Traditional = 2, - English = 3, - French = 4, - German = 5, - Italian = 6, - Korean = 7, - Polish = 8, - Brazilian_Portuguese = 9, - Russian = 10, - Spanish = 11, - Latin_American_Spanish = 12, - Turkey = 13, - Czech = 14, - Danish = 15, - Swedish = 16, - Hungary = 17, - Slovak = 18, - Finnish = 19, - Lithuanian = 20, - Custom = 21, -} - internal class Translation { public const Languages DEFAULT_LANGUAGE = Languages.English; @@ -90,7 +64,11 @@ internal static string GetString(string key) else return key.Replace(keyClean, CustomTranslation.customStr[key]); } - if (data.ContainsKey((int)Main.Language)) return key.Replace(keyClean, data[(int)Main.Language]); + if (data.ContainsKey((int)Main.Language)) + { + if (data[(int)Main.Language] is "[EN]") key.Replace(keyClean, data[(int)DEFAULT_LANGUAGE]); + else return key.Replace(keyClean, data[(int)Main.Language]); + } else if (data.ContainsKey((int)DEFAULT_LANGUAGE)) return key.Replace(keyClean, data[(int)DEFAULT_LANGUAGE]); Logger.Warn($"Translate key was not found in dictionary. Key: {key}", "Translate"); @@ -100,7 +78,7 @@ internal static string GetString(string key) internal static void SetLanguage(Languages id, bool showNotification = true) { Main.Language = id; - DynamicMenu.UpdateTranslate(); + ContextMenu.UpdateTranslate(); if (showNotification) MessageExtensions.SendMessageInGame(string.Format($"The language was set to {Enum.GetName(typeof(Languages), id).Replace("_", " ")} now.")); } diff --git a/DynamicLSPDFR/Extensions/LocationExtensions.cs b/DynamicLSPDFR/Extensions/LocationExtensions.cs deleted file mode 100644 index 0021635..0000000 --- a/DynamicLSPDFR/Extensions/LocationExtensions.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class LocationExtensions -{ - internal static T GetNearestPosition(Dictionary SpawnPoints) - { - Dictionary distances = new(); - List Keys = SpawnPoints.Values.ToList(); - List Values = SpawnPoints.Keys.ToList(); - - for (int i = 0; i < SpawnPoints.Count; i++) - { - var pPos = Game.LocalPlayer.Character.Position; - distances.Add((Keys[i] - pPos).Length(), Values[i]); - } - - return distances[distances.Keys.ToList().Min()]; - } - - internal static List GetNearestPositionFromNum(Dictionary SpawnPoints, int count) - { - Dictionary distances = new(); - List Keys = SpawnPoints.Values.ToList(); - List Values = SpawnPoints.Keys.ToList(); - - for (int i = 0; i < SpawnPoints.Count; i++) - { - var pPos = Game.LocalPlayer.Character.Position; - distances.Add((Keys[i] - pPos).Length(), Values[i]); - } - - List list = new(); - for (int i = 0; i < count; i++) - { - list.Add(distances[distances.Keys.ToList().Min()]); - distances.Remove(distances.Keys.ToList().Min()); - } - return list; - } - - internal static List GetNearestPositionFromNum(Dictionary SpawnPoints, int count) - { - Dictionary distances = new(); - List Keys = new(); - foreach (var sp in SpawnPoints) Keys.Add(sp.Value.Item1); - List Values = SpawnPoints.Keys.ToList(); - - for (int i = 0; i < SpawnPoints.Count; i++) - { - var pPos = Game.LocalPlayer.Character.Position; - distances.Add((Keys[i] - pPos).Length(), Values[i]); - } - - List list = new(); - for (int i = 0; i < count; i++) - { - list.Add(distances[distances.Keys.ToList().Min()]); - distances.Remove(distances.Keys.ToList().Min()); - } - return list; - } -} - -internal static class LocationExtensions -{ - internal static string GetLocationName() - { - return Functions.GetZoneAtPosition(Game.LocalPlayer.Character.Position).GameName; - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/LoggerExtensions.cs b/DynamicLSPDFR/Extensions/LoggerExtensions.cs deleted file mode 100644 index 10ee395..0000000 --- a/DynamicLSPDFR/Extensions/LoggerExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal enum LogType : int -{ - Info, - Warning, - Error, - ErrorCode, - Trace, -} - -internal static class Logger -{ - internal static void Info(string text, string tag = "") => Log(text, LogType.Info, tag); - internal static void Warn(string text, string tag = "") => Log(text, LogType.Warning, tag); - internal static void Error(string text, string tag = "", int errorCode = 0) => Log(text, LogType.Error, tag, errorCode); - internal static void ErrorCode(string tag, int errorCode) => Log("An error has occurred.", LogType.ErrorCode, tag, errorCode); - internal static void Trace(string text, string tag = "") => Log(text, LogType.Trace, tag); - - private static void Log(string text, LogType type = LogType.Trace, string tag = "", int errorCode = 0) - { - if (string.IsNullOrEmpty(text) || string.IsNullOrWhiteSpace(text)) return; - StringBuilder sb = new(); - if (string.IsNullOrEmpty(tag) || string.IsNullOrWhiteSpace(tag)) sb.Append("[").Append(type.ToString()).Append("] "); - else - { - if (type is not LogType.ErrorCode) sb.Append("[").Append(type.ToString()).Append("] [").Append(tag).Append("] "); - } - if (errorCode is not 0) sb.Append("[").Append(tag).Append("] [ErrorCode: ").Append(errorCode).Append("]"); - sb.Append(text); - Game.Console.Print(sb.ToString()); - - if (type is LogType.ErrorCode) - { - // MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("ErrorOccurred"), errorCode)); - // MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("PleaseReport"))); - MessageExtensions.SendMessageInGame(string.Format($"~h~[DynamicLSPDFR]~h~\n~y~An error has occurred.~s~\n~y~Error Code: {errorCode}~s~")); - MessageExtensions.SendMessageInGame(string.Format("~r~Please report your bug in my ~p~Discord Server~r~!~s~")); - } - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/MathExtensions.cs b/DynamicLSPDFR/Extensions/MathExtensions.cs index aee65c5..c5600a7 100644 --- a/DynamicLSPDFR/Extensions/MathExtensions.cs +++ b/DynamicLSPDFR/Extensions/MathExtensions.cs @@ -1,8 +1,8 @@ namespace DynamicLSPDFR.Extensions; -internal static class MathExtensions +public static class MathExtensions { - internal static int GetVehicleFromChance(int[] chances) + public static int GetVehicleFromChance(int[] chances) { var total = 0; var table = new int[chances.Length]; diff --git a/DynamicLSPDFR/Extensions/MessageExtensions.cs b/DynamicLSPDFR/Extensions/MessageExtensions.cs index 9cebbc6..c2d2791 100644 --- a/DynamicLSPDFR/Extensions/MessageExtensions.cs +++ b/DynamicLSPDFR/Extensions/MessageExtensions.cs @@ -6,10 +6,7 @@ internal static class MessageExtensions /// Normal Message send in game. /// /// message - internal static void SendMessageInGame(string text) - { - Game.DisplayNotification(text); - } + internal static void SendMessageInGame(string text) => Game.DisplayNotification(text); /// /// Send message with picture. diff --git a/DynamicLSPDFR/Extensions/NativeExtensions.cs b/DynamicLSPDFR/Extensions/NativeExtensions.cs deleted file mode 100644 index 7749cc6..0000000 --- a/DynamicLSPDFR/Extensions/NativeExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class NativeExtensions -{ - internal static void Drive(Vehicle veh, float speed) => NativeFunction.Natives.SET_VEHICLE_FORWARD_SPEED(veh, speed); - // internal static WeatherHash GetWorldWeather() - // { - // try - // { - // return NativeFunction.Natives.GET_NEXT_WEATHER_TYPE_HASH_NAME(); - // } - // catch (Exception e) - // { - // Logger.Error(e.ToString(), "Weather Getter"); - // return WeatherHash.EXTRA_SUNNY; - // } - // } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/PedExtensions.cs b/DynamicLSPDFR/Extensions/PedExtensions.cs deleted file mode 100644 index cf1122b..0000000 --- a/DynamicLSPDFR/Extensions/PedExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class PedExtensions -{ - internal static bool IsDeadOrArrested(this Ped ped) - { - if (ped && ped.IsValid() && (ped.IsDead || Functions.IsPedArrested(ped))) return true; - else return false; - } - - internal static bool EveryoneAreDeadOrArrested(params Ped[] peds) - { - for (int i = 0; i < peds.Length; i++) - { - if ((peds[i] && peds[i].IsValid() && peds[i].IsDeadOrArrested()) || !peds[i]) continue; - else return false; - } - return true; - } - - internal static void SetTeamAndFight(string teamName, params Ped[] peds) - { - for (int i = 0; i < peds.Length; i++) - { - if (peds[i] && peds[i].IsValid()) - { - peds[i].RelationshipGroup = teamName; - peds[i].Tasks.FightAgainstClosestHatedTarget(3000f); - } - } - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector2Converter.cs b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector2Converter.cs new file mode 100644 index 0000000..1b67d19 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector2Converter.cs @@ -0,0 +1,21 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Converters; + +public class Vector2Converter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Vector2); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var val = JObject.Load(reader); + return new Vector2((float)val["x"], (float)val["y"]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var val = (Vector2)value; + serializer.Serialize(writer, new { val.X, val.Y, }); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector3Converter.cs b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector3Converter.cs new file mode 100644 index 0000000..a5f4ef1 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector3Converter.cs @@ -0,0 +1,21 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Converters; + +public class Vector3Converter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Vector3); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var val = JObject.Load(reader); + return new Vector3((float)val["x"], (float)val["y"], (float)val["z"]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var val = (Vector3)value; + serializer.Serialize(writer, new { val.X, val.Y, val.Z }); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector4Converter.cs b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector4Converter.cs new file mode 100644 index 0000000..8f3b341 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Converters/Vector4Converter.cs @@ -0,0 +1,21 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Converters; + +public class Vector4Converter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Vector4); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var val = JObject.Load(reader); + return new Vector4((float)val["x"], (float)val["y"], (float)val["z"], (float)val["w"]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var val = (Vector4)value; + serializer.Serialize(writer, new { val.X, val.Y, val.Z, val.W }); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Serializer/JsonSerialiser.cs b/DynamicLSPDFR/Extensions/Save/Core/Serializer/JsonSerialiser.cs new file mode 100644 index 0000000..1e5a097 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Serializer/JsonSerialiser.cs @@ -0,0 +1,20 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Serializers; + +public static class Serializer +{ + private static readonly JsonSerializerSettings settings = new() + { + Converters = new List() + { + new Vector2Converter(), + new Vector3Converter(), + new Vector4Converter() + } + }; + + private static JsonSerializer serializer = JsonSerializer.Create(settings); + + public static T DeserializeKey(string key, JObject data) => data[key].ToObject(serializer); + public static JToken SerializeKey(T data) => JToken.FromObject(data, serializer); + public static string Serialize(T value) => JsonConvert.SerializeObject(value, settings); +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Settings/Compression.cs b/DynamicLSPDFR/Extensions/Save/Core/Settings/Compression.cs new file mode 100644 index 0000000..2271812 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Settings/Compression.cs @@ -0,0 +1,40 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Settings; + +public class Compression +{ + public static string Compress(string value, CompressionMode compressionMode) + { + if (compressionMode is CompressionMode.None) return value; + + var bytes = Encoding.UTF8.GetBytes(value); + + using (var streamIn = new MemoryStream(bytes)) + using (var streamOut = new MemoryStream()) + { + using (var compressionStream = new GZipStream(streamOut, System.IO.Compression.CompressionMode.Compress)) + { + streamIn.CopyTo(compressionStream); + } + + return Convert.ToBase64String(streamOut.ToArray()); + } + } + + public static string Decompress(string value, CompressionMode compressionMode) + { + if (compressionMode is CompressionMode.None) return value; + + var bytes = Convert.FromBase64String(value); + + using (var streamIn = new MemoryStream(bytes)) + using (var streamOut = new MemoryStream()) + { + using (var compressionStream = new GZipStream(streamIn, System.IO.Compression.CompressionMode.Decompress)) + { + compressionStream.CopyTo(streamOut); + } + + return Encoding.UTF8.GetString(streamOut.ToArray()); + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Settings/Cryptography.cs b/DynamicLSPDFR/Extensions/Save/Core/Settings/Cryptography.cs new file mode 100644 index 0000000..c633b73 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Settings/Cryptography.cs @@ -0,0 +1,79 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Settings; + +public static class Cryptography +{ + public static string Encrypt(string value, SecurityMode securityMode, string password) + { + switch (securityMode) + { + case SecurityMode.Aes: return AesEncrypt(password, value); + case SecurityMode.Base64: return Base64Encode(value); + default: return value; + } + } + + public static string Decrypt(string value, SecurityMode securityMode, string password) + { + switch (securityMode) + { + case SecurityMode.Aes: return AesDecrypt(password, value); + case SecurityMode.Base64: return Base64Decode(value); + default: return value; + } + } + + private static string AesEncrypt(string encryptionKey, string value) + { + if (string.IsNullOrEmpty(value)) return value; + + using (var encryptor = Aes.Create()) + { + Rfc2898DeriveBytes pdb = new(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); + + encryptor.Key = pdb.GetBytes(32); + encryptor.IV = pdb.GetBytes(16); + + byte[] bytes = Encoding.UTF8.GetBytes(value); + + using (var streamIn = new MemoryStream(bytes)) + using (var streamOut = new MemoryStream()) + { + using (var cryptoStream = new CryptoStream(streamOut, encryptor.CreateEncryptor(), CryptoStreamMode.Write)) + { + streamIn.CopyTo(cryptoStream); + } + + return Convert.ToBase64String(streamOut.ToArray()); + } + } + } + + private static string AesDecrypt(string encryptionKey, string value) + { + if (string.IsNullOrEmpty(value)) return value; + + using (var decryptor = Aes.Create()) + { + Rfc2898DeriveBytes pdb = new(encryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); + + decryptor.Key = pdb.GetBytes(32); + decryptor.IV = pdb.GetBytes(16); + + byte[] bytes = Convert.FromBase64String(value); + + using (var streamIn = new MemoryStream(bytes)) + using (var streamOut = new MemoryStream()) + { + using (var cryptoStream = new CryptoStream(streamIn, decryptor.CreateDecryptor(), CryptoStreamMode.Read)) + { + cryptoStream.CopyTo(streamOut); + } + + return Encoding.UTF8.GetString(streamOut.ToArray()); + } + } + } + + private static string Base64Encode(string value) => Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); + private static string Base64Decode(string value) => Encoding.UTF8.GetString(Convert.FromBase64String(value)); +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/Core/Storage/FileAccess.cs b/DynamicLSPDFR/Extensions/Save/Core/Storage/FileAccess.cs new file mode 100644 index 0000000..3f10228 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/Core/Storage/FileAccess.cs @@ -0,0 +1,134 @@ +namespace DynamicLSPDFR.Extensions.Save.Core.Storage; + +public static class FileAccess +{ + private const string FILE_EXTENSIONS = ".dat"; + + private static string BasePath => Path.Combine(SaveExtensions.SAVE_FOLDER_PATH, "SaveData"); + + public static bool SaveString(string filename, bool includesExtension, string value) + { + filename = GetFilenameWithExtension(filename, includesExtension); + + try + { + CreateRootFolder(); + + using (StreamWriter writer = new(Path.Combine(BasePath, filename))) + { + writer.Write(value); + } + + return true; + } + catch { } + + return false; + } + + public static bool SaveBytes(string filename, bool includesExtension, byte[] value) + { + filename = GetFilenameWithExtension(filename, includesExtension); + + try + { + CreateRootFolder(); + + using (FileStream fileStream = new(Path.Combine(BasePath, filename), FileMode.Create)) + { + fileStream.Write(value, 0, value.Length); + } + + return true; + } + catch { } + + return false; + } + + public static string LoadString(string filename, bool includesExtension) + { + filename = GetFilenameWithExtension(filename, includesExtension); + + try + { + CreateRootFolder(); + + if (Exists(filename, true)) + { + using (StreamReader reader = new(Path.Combine(BasePath, filename))) + { + return reader.ReadToEnd(); + } + } + } + catch { } + + return null; + } + + public static byte[] LoadBytes(string filename, bool includesExtension) + { + filename = GetFilenameWithExtension(filename, includesExtension); + + try + { + CreateRootFolder(); + + if (Exists(filename, true)) + { + using (FileStream fileStream = new(Path.Combine(BasePath, filename), FileMode.Open)) + { + byte[] buffer = new byte[fileStream.Length]; + + fileStream.Read(buffer, 0, buffer.Length); + + return buffer; + } + } + } + catch { } + + return null; + } + + public static void Delete(string filename, bool includesExtension) + { + filename = GetFilenameWithExtension(filename, includesExtension); + + try + { + CreateRootFolder(); + string fileLocation = Path.Combine(BasePath, filename); + File.Delete(fileLocation); + } + catch { } + } + + public static bool Exists(string filename, bool includesExtension) + { + filename = GetFilenameWithExtension(filename, includesExtension); + string fileLocation = Path.Combine(BasePath, filename); + return File.Exists(fileLocation); + } + + public static IEnumerable Files(bool includeExtensions) + { + try + { + CreateRootFolder(); + + if (includeExtensions) return Directory.GetFiles(BasePath, "*.dat").Select(x => Path.GetFileName(x)); + else return Directory.GetFiles(BasePath, "*.dat").Select(x => Path.GetFileNameWithoutExtension(x)); + } + catch { } + + return new List(); + } + + private static string GetFilenameWithExtension(string filename, bool includesExtension) => includesExtension ? filename : new StringBuilder(filename).Append(FILE_EXTENSIONS).ToString(); + private static void CreateRootFolder() + { + if (!Directory.Exists(BasePath)) Directory.CreateDirectory(BasePath); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/SaveBase.cs b/DynamicLSPDFR/Extensions/Save/SaveBase.cs new file mode 100644 index 0000000..b7a6ec7 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/SaveBase.cs @@ -0,0 +1,118 @@ +namespace DynamicLSPDFR.Extensions.Save; + +public abstract class SaveBase +{ + protected JObject items; + protected string root; + protected SaveSettings settings; + + /// + /// Determines if the specified key exists + /// + /// The key to look for + /// Does the key exist + public bool Exists(string key) => items[key] != null; + + /// + /// Gets the names of all the keys under this root + /// + /// A collection of key names + public IEnumerable GetAllKeys() => items.Properties().Select(x => x.Name).ToList(); + + protected void Load(bool rootMightNotExist) + { + var json = FileAccess.LoadString(root, false); + + if (string.IsNullOrEmpty(json)) + { + if (rootMightNotExist) + { + items = new(); + return; + } + + // Logger.ErrorCode("Load", 65); + Logger.Error("The file is empty."); + } + + // Gzip parses base64 anyway so no need to do it twice + if (settings.CompressionMode is not CompressionMode.Gzip || settings.SecurityMode is not SecurityMode.Base64) + { + try + { + json = Cryptography.Decrypt(json, settings.SecurityMode, settings.Password); + } + catch (Exception e) + { + Logger.ErrorCode("Load", 66); + Logger.Error(e.ToString()); + } + } + + try + { + json = Compression.Decompress(json, settings.CompressionMode); + } + catch (Exception e) + { + Logger.ErrorCode("Load", 67); + Logger.Error(e.ToString()); + } + + try + { + items = JObject.Parse(json); + } + catch (NullReferenceException e) + { + Logger.Error("The file doesn't have any data."); + Logger.Error(e.ToString()); + } + catch (Exception e) + { + Logger.ErrorCode("Load", 68); + Logger.Error(e.ToString()); + } + } + + protected void Save() + { + string json = ""; + + try + { + json = Serializer.Serialize(items); + } + catch (Exception e) + { + Logger.ErrorCode("Save", 69); + Logger.Error(e.ToString()); + } + + try + { + json = Compression.Compress(json, settings.CompressionMode); + } + catch (Exception e) + { + Logger.ErrorCode("Save", 70); + Logger.Error(e.ToString()); + } + + // Gzip outputs base64 anyway so no need to do it twice + if (settings.CompressionMode is not CompressionMode.Gzip || settings.SecurityMode is not SecurityMode.Base64) + { + try + { + json = Cryptography.Encrypt(json, settings.SecurityMode, settings.Password); + } + catch (Exception e) + { + Logger.ErrorCode("Save", 71); + Logger.Error(e.ToString()); + } + } + + if (!FileAccess.SaveString(root, false, json)) Logger.ErrorCode("Save", 72); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/SaveRaw.cs b/DynamicLSPDFR/Extensions/Save/SaveRaw.cs new file mode 100644 index 0000000..413c352 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/SaveRaw.cs @@ -0,0 +1,136 @@ +// namespace DynamicLSPDFR.Extensions.Save; + +// public class SaveRaw +// { +// /// +// /// Saves a string directly to the specified file, overwriting if it already exists +// /// +// /// The file to save to +// /// The string to save +// public static void SaveString(string filename, string content) => SaveString(filename, content, new SaveSettings()); + +// /// +// /// Saves a string directly to the specified file using the specified settings, overwriting if it already exists +// /// +// /// The file to save to +// /// The string to save +// /// Settings +// public static void SaveString(string filename, string content, SaveSettings settings) +// { +// string contentToWrite; + +// try +// { +// contentToWrite = Compression.Compress(content, settings.CompressionMode); +// } +// catch (Exception e) +// { +// throw new DynamicLSPDFRException("Compression failed", e); +// } + +// // Gzip outputs base64 anyway so no need to do it twice +// if (settings.CompressionMode is not CompressionMode.Gzip || settings.SecurityMode is not SecurityMode.Base64) +// { +// try +// { +// contentToWrite = Cryptography.Encrypt(contentToWrite, settings.SecurityMode, settings.Password); +// } +// catch (Exception e) +// { +// throw new DynamicLSPDFRException("Encryption failed", e); +// } +// } + +// if (!FileAccess.SaveString(filename, true, contentToWrite)) +// { +// throw new DynamicLSPDFRException("Failed to write to file"); +// } +// } + +// /// +// /// Saves a byte array directly to the specified file, overwriting if it already exists +// /// +// /// The file to save to +// /// The byte array to save +// public static void SaveBytes(string filename, byte[] content) +// { +// if (!FileAccess.SaveBytes(filename, true, content)) throw new DynamicLSPDFRException("Failed to write to file"); +// } + +// /// +// /// Loads the contents of the specified file into a string +// /// +// /// The file to load from +// /// The contents of the file as a string +// public static string LoadString(string filename) => LoadString(filename, new SaveSettings()); + +// /// +// /// Loads the contents of the specified file into a string using the specified settings +// /// +// /// The file to load from +// /// Settings +// /// The contents of the file as a string +// public static string LoadString(string filename, SaveSettings settings) +// { +// var content = FileAccess.LoadString(filename, true); + +// if (content is null) throw new DynamicLSPDFRException("Failed to load file"); + +// // Gzip parses base64 anyway so no need to do it twice +// if (settings.CompressionMode is not CompressionMode.Gzip || settings.SecurityMode is not SecurityMode.Base64) +// { +// try +// { +// content = Cryptography.Decrypt(content, settings.SecurityMode, settings.Password); +// } +// catch (Exception e) +// { +// throw new DynamicLSPDFRException("Decryption failed", e); +// } +// } + +// try +// { +// content = Compression.Decompress(content, settings.CompressionMode); +// } +// catch (Exception e) +// { +// throw new DynamicLSPDFRException("Decompression failed", e); +// } + +// return content; +// } + +// /// +// /// Loads the contents of the specified file into a byte array +// /// +// /// The file to load from +// /// The contents of the file as a byte array +// public static byte[] LoadBytes(string filename) +// { +// byte[] content = FileAccess.LoadBytes(filename, true); + +// if (content is null) throw new DynamicLSPDFRException("Failed to load file"); + +// return content; +// } + +// /// +// /// Deletes the specified file if it exists +// /// +// /// The file to delete +// public static void Delete(string filename) => FileAccess.Delete(filename, true); + +// /// +// /// Determines if the specified file exists +// /// +// /// The file to check +// /// Does the file exist +// public static bool Exists(string filename) => FileAccess.Exists(filename, true); + +// /// +// /// Gets the names of all files that have been saved +// /// +// /// A collection of file names +// public static IEnumerable GetAllFiles() => FileAccess.Files(false); +// } \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/SaveReader.cs b/DynamicLSPDFR/Extensions/Save/SaveReader.cs new file mode 100644 index 0000000..ee397d5 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/SaveReader.cs @@ -0,0 +1,105 @@ +namespace DynamicLSPDFR.Extensions.Save; + +public class SaveReader : SaveBase +{ + private SaveReader(string root, SaveSettings settings) + { + base.root = root; + base.settings = settings; + } + + /// + /// Creates a SaveReader on the specified root + /// + /// The root to read from + /// A SaveReader instance + public static SaveReader Create(string root) => Create(root, new SaveSettings()); + + /// + /// Creates a SaveReader on the specified root using the specified settings + /// + /// The root to read from + /// Settings + /// A SaveReader instance + public static SaveReader Create(string root, SaveSettings settings) + { + SaveReader SaveReader = new(root, settings); + SaveReader.Load(false); + return SaveReader; + } + + /// + /// Reads an object under the specified key + /// + /// The type of object to read + /// The key this object was saved under + /// The object that was loaded + public T Read(string key) + { + if (!Exists(key)) Logger.ErrorCode("Save", 73); + + try + { + return Serializer.DeserializeKey(key, items); + } + catch + { + Logger.ErrorCode("Save", 74); + throw new Exception("Failed to deserialization"); + } + } + + /// + /// Reads an object under the specified key + /// + /// The type of object to read + /// The key this object was saved under + /// An action to be called when the read completes + /// The SaveReader + public SaveReader Read(string key, Action result) + { + if (!Exists(key)) Logger.ErrorCode("Save", 73); + + try + { + result(Serializer.DeserializeKey(key, items)); + } + catch + { + Logger.ErrorCode("Save", 74); + throw new Exception("Failed to deserialization"); + } + + return this; + } + + /// + /// Attempts to read an object under the specified key + /// + /// The type of object to read + /// The key this object was saved under + /// The object that was loaded + /// Was the read successful + public bool TryRead(string key, out T result) + { + result = default(T); + + if (!Exists(key)) return false; + + try + { + result = Serializer.DeserializeKey(key, items); + + return true; + } + catch + { + return false; + } + } + + /// + /// Reloads data from the root + /// + public void Reload() => Load(false); +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/SaveSettings.cs b/DynamicLSPDFR/Extensions/Save/SaveSettings.cs new file mode 100644 index 0000000..3175d41 --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/SaveSettings.cs @@ -0,0 +1,26 @@ +namespace DynamicLSPDFR.Extensions.Save +{ + public class SaveSettings + { + /// + /// The type of encryption to use on the data + /// + public SecurityMode SecurityMode { get; set; } + + /// + /// The type of compression to use on the data + /// + public CompressionMode CompressionMode { get; set; } + + /// + /// If aes is selected as the security mode specify a password to use as the encryption key + /// + public string Password { get; set; } + + public SaveSettings() + { + SecurityMode = SecurityMode.None; + CompressionMode = CompressionMode.None; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/Save/SaveWriter.cs b/DynamicLSPDFR/Extensions/Save/SaveWriter.cs new file mode 100644 index 0000000..e6a9c4f --- /dev/null +++ b/DynamicLSPDFR/Extensions/Save/SaveWriter.cs @@ -0,0 +1,77 @@ +namespace DynamicLSPDFR.Extensions.Save; + +public class SaveWriter : SaveBase +{ + private SaveWriter(string root, SaveSettings settings) + { + base.root = root; + base.settings = settings; + } + + /// + /// Creates a SaveWriter on the specified root + /// + /// The root to write to + /// A SaveWriter instance + public static SaveWriter Create(string root) => Create(root, new()); + + /// + /// Creates a SaveWriter on the specified root using the specified settings + /// + /// The root to write to + /// Settings + /// A SaveWriter instance + public static SaveWriter Create(string root, SaveSettings settings) + { + SaveWriter SaveWriter = new(root, settings); + SaveWriter.Load(true); + return SaveWriter; + } + + /// + /// Writes an object to the specified key - you must called commit to write the data to file + /// + /// The type of object to write + /// The key this object will be saved under + /// The object to save + /// The SaveWriter + public SaveWriter Write(string key, T value) + { + if (Exists(key)) items.Remove(key); + + items.Add(key, Serializer.SerializeKey(value)); + + return this; + } + + /// + /// Deletes the specified key if it exists + /// + /// The key to delete + public void Delete(string key) + { + if (Exists(key)) items.Remove(key); + } + + /// + /// Commits the changes to file + /// + public void Commit() => Save(); + + /// + /// Attempts to commit the changes to file + /// + /// Was the commit successful + public bool TryCommit() + { + try + { + Save(); + return true; + } + catch + { + return false; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/SaveExtensions.cs b/DynamicLSPDFR/Extensions/SaveExtensions.cs new file mode 100644 index 0000000..f993b49 --- /dev/null +++ b/DynamicLSPDFR/Extensions/SaveExtensions.cs @@ -0,0 +1,19 @@ +namespace DynamicLSPDFR.Extensions; + +public enum SecurityMode +{ + None, + Aes, + Base64 +} + +public enum CompressionMode +{ + None, + Gzip +} + +public static class SaveExtensions +{ + public const string SAVE_FOLDER_PATH = @"plugins/LSPDFR/DynamicLSPDFR"; +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/VehicleExtensions.cs b/DynamicLSPDFR/Extensions/VehicleExtensions.cs new file mode 100644 index 0000000..9795cb0 --- /dev/null +++ b/DynamicLSPDFR/Extensions/VehicleExtensions.cs @@ -0,0 +1,25 @@ +namespace DynamicLSPDFR.Extensions; + +public static class VehicleExtensions +{ + public static Model[] LSPDVehicles = new Model[] { "POLICE", "POLICE2", "POLICE3" }; + public static Model[] LSSDVehicles = new Model[] { "SHERIFF", "SHERIFF2" }; + public static Model[] NorthYanktonPDVehicles = new Model[] { "POLICEOLD1", "POLICEOLD2" }; + + public static Model GetPoliceVehicleFromCounty() + { + switch (Main.CurrentPlayerCountry) + { + default: + case EWorldZoneCounty.CayoPerico: + case EWorldZoneCounty.LosSantos: + case EWorldZoneCounty.SanAndreas: + return LSPDVehicles[RandomNumber.Instance.Next(LSPDVehicles.Length)]; + case EWorldZoneCounty.LosSantosCounty: + case EWorldZoneCounty.BlaineCounty: + return LSSDVehicles[RandomNumber.Instance.Next(LSSDVehicles.Length)]; + case EWorldZoneCounty.NorthYankton: + return NorthYanktonPDVehicles[RandomNumber.Instance.Next(NorthYanktonPDVehicles.Length)]; + } + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Extensions/WeatherExtensions.cs b/DynamicLSPDFR/Extensions/WeatherExtensions.cs deleted file mode 100644 index f255406..0000000 --- a/DynamicLSPDFR/Extensions/WeatherExtensions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace DynamicLSPDFR.Extensions; - -internal static class WeatherExtensions -{ - internal static WeatherHash GetCurrentWeather() - { - return (WeatherHash)NativeFunction.CallByHash(0x564B884A05EC45A3); - } -} \ No newline at end of file diff --git a/DynamicLSPDFR/Main.cs b/DynamicLSPDFR/Main.cs index f818dd3..ac13f37 100644 --- a/DynamicLSPDFR/Main.cs +++ b/DynamicLSPDFR/Main.cs @@ -3,24 +3,39 @@ global using System.Net; global using System.Reflection; global using System.Drawing; +global using System.Diagnostics; global using System.IO; -global using System.Resources; +global using System.IO.Compression; +global using System.Security.Cryptography; +global using System.Text; global using System.Windows.Forms; global using System.Collections.Generic; -global using System.Text; global using System.Text.RegularExpressions; -global using System.Xml; +global using System.Xml.Serialization; global using DynamicLSPDFR.Callouts; -global using DynamicLSPDFR.Common; global using DynamicLSPDFR.Debug; global using DynamicLSPDFR.Extensions; global using DynamicLSPDFR.Extensions.Random; +global using DynamicLSPDFR.Extensions.Save; global using DynamicLSPDFR.Extensions.Localization; global using DynamicLSPDFR.Modules; global using DynamicLSPDFR.Patches; global using DynamicLSPDFR.Settings; +global using DynamicLSPDFR.Units; global using DynamicLSPDFR.Update; +global using DynamicLSPDFR.Utilities; +global using ContextMenu = DynamicLSPDFR.Modules.DynamicMenu.ContextMenu; +global using CalloutsMenu = DynamicLSPDFR.Modules.DynamicMenu.CalloutsMenu; +global using LanguageMenu = DynamicLSPDFR.Modules.DynamicMenu.LanguageMenu; +global using PylonsMenu = DynamicLSPDFR.Modules.DynamicMenu.PylonsMenu; +global using TrafficMenu = DynamicLSPDFR.Modules.DynamicMenu.TrafficMenu; +global using DynamicLSPDFR.Extensions.Save.Core.Converters; +global using DynamicLSPDFR.Extensions.Save.Core.Serializers; +global using DynamicLSPDFR.Extensions.Save.Core.Settings; +global using DynamicLSPDFR.Extensions.Save.Core.Storage; +global using FileAccess = DynamicLSPDFR.Extensions.Save.Core.Storage.FileAccess; +global using CompressionMode = DynamicLSPDFR.Extensions.CompressionMode; global using Rage; global using Rage.Native; @@ -32,9 +47,14 @@ global using LSPD_First_Response.Mod.API; global using LSPD_First_Response.Mod.Callouts; global using LSPD_First_Response.Engine.Scripting; +global using LSPD_First_Response.Mod.Menus; global using RAGENativeUI; global using RAGENativeUI.Elements; +global using RAGENativeUI.PauseMenu; global using static RAGENativeUI.Common; +global using DekoKiyoCommonLibrary.Common; +global using DekoKiyoCommonLibrary.Extensions; +global using Newtonsoft.Json; global using Newtonsoft.Json.Linq; namespace DynamicLSPDFR; @@ -44,11 +64,25 @@ internal class Main : Plugin internal const string PLUGIN_NAME = "Dynamic LSPDFR"; internal static readonly Version PLUGIN_VERSION = Assembly.GetExecutingAssembly().GetName().Version; internal static readonly string PLUGIN_VERSION_STRING = PLUGIN_VERSION.ToString(); + internal const string LSPDFR_DLL_FILE_PATH = @"plugins/LSPD First Response.dll"; + internal const string RPH_APPLICATION_PATH = @"RAGEPluginHook.exe"; + internal const string NEWTONSOFT_JSON_DLL_FILE_PATH = @"Newtonsoft.Json.dll"; + internal const string RAGE_NATIVE_UI_DLL_FILE_PATH = @"RAGENativeUI.dll"; + internal static readonly Version GTA5_VERSION = new("1.0.2845.0"); + internal static readonly Version LSPDFR_VERSION = new("0.4.9.0"); + internal static readonly Version MINIMUM_RAGE_PLUGIN_HOOK_VERSION = new("1.98.1315.16379"); + internal static readonly Version NEWTONSOFT_JSON_DLL_VERSION = new("13.0.2.27524"); + internal static readonly Version RAGE_NATIVE_UI_DLL_VERSION = new("1.9.2.0"); + internal static readonly string PluginInfo = new StringBuilder(RSFormat.Bold).Append(RSFormat.ColorBlue).Append("DynamicLSPDFR").Append(RSFormat.Default).Append(RSFormat.Bold).Append(" Version.").Append(RSFormat.ColorOrange).Append(Main.PLUGIN_VERSION_STRING).Append(RSFormat.Default).ToString(); internal static EWorldZoneCounty CurrentPlayerCountry = EWorldZoneCounty.LosSantos; internal static Keys OpenContextMenuKey { get; set; } = Keys.O; internal static Keys OpenContextMenuModifierKey { get; set; } = Keys.None; + // internal static Keys OpenTrafficTicketsMenuKey { get; set; } = Keys.U; + // internal static Keys OpenTrafficTicketsMenuModifierKey { get; set; } = Keys.LControlKey; + internal static Keys UnitsTeleportToNearbyPlayerKey { get; set; } = Keys.U; + internal static Keys UnitsTeleportToNearbyPlayerModifierKey { get; set; } = Keys.LControlKey; internal static string OfficerName { get; set; } = "Officer"; internal static string StationName { get; set; } = ""; @@ -56,6 +90,8 @@ internal class Main : Plugin internal static Languages Language { get; set; } = Languages.English; internal static Algorithm Random { get; set; } = Algorithm.SystemRandom; + internal static float CoronerSpawnDistance { get; set; } = 120f; + /// /// LSPDFR初期化 /// @@ -83,38 +119,45 @@ private static void OnDutyStateChanged(bool OnDuty) // Stop if not duty. if (!OnDuty) { - DynamicMenu.Reset(); + ContextMenu.Reset(); #if Dev ShowPlayerPosition.Remove(); #endif } else { - Translation.Load(); - ClientSettings.LoadSettings(); - Game.AddConsoleCommands(); - DynamicMenu.Initialize(); - CalloutList.RegisterCallouts(); - PylonsManager.Initialize(); - KeyDown.StartUpdate(); - RandomNumber.SetInstance(Random); - // Overlay.Initialize(); - - GameFiber.StartNew(() => + if (VersionChecker.CheckLSPDFRVersion()) { - while (true) + Translation.Load(); + CoronerReport.Initialize(); + ContextMenu.SetupContextMenu(); + ClientSettings.LoadSettings(); + Game.AddConsoleCommands(); + CalloutBase.InitializeCallouts(); + PylonsManager.Initialize(); + KeyDown.StartUpdate(); + RandomNumber.SetInstance(Random); + // Overlay.Initialize(); + + GameFiber.StartNew(UpdateChecker.CheckUpdate); + GameFiber.StartNew(() => { - GameFiber.Yield(); - Main.CurrentPlayerCountry = Functions.GetZoneAtPosition(Game.LocalPlayer.Character.Position).County; - } - }); + while (true) + { + GameFiber.Yield(); + Main.CurrentPlayerCountry = Functions.GetZoneAtPosition(Game.LocalPlayer.Character.Position).County; + } + }); #if Dev - ShowPlayerPosition.SetBar(); + ShowPlayerPosition.SetBar(); #endif - - MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("LoadMessage"), PLUGIN_NAME), PLUGIN_NAME, new StringBuilder("Version.").Append(PLUGIN_VERSION_STRING).ToString()); - if (UpdateChecker.HasUpdate()) MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("UpdateMessage"), PLUGIN_NAME), PLUGIN_NAME, Translation.GetString("UpdateAvailable")); + GameFiber.StartNew(() => + { + GameFiber.Wait(8000); + MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("LoadMessage"), PLUGIN_NAME), PLUGIN_NAME, new StringBuilder("Version.").Append(PLUGIN_VERSION_STRING).ToString()); + }, "[DynamicLSPDFR] First Message"); + } } } } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/DynamicMenu/ContextMenu.cs b/DynamicLSPDFR/Modules/DynamicMenu/ContextMenu.cs deleted file mode 100644 index fae2e4a..0000000 --- a/DynamicLSPDFR/Modules/DynamicMenu/ContextMenu.cs +++ /dev/null @@ -1,510 +0,0 @@ -namespace DynamicLSPDFR.Modules; - -internal static class DynamicMenu -{ - private const string BANNER_PATH = "DynamicLSPDFR.Resources.Images.Banner.png"; - - // Pool - private static MenuPool Pool; - - // Context Menu - private static UIMenu ContextMenu; - private static UIMenuItem LanguageSelectItem; - internal static UIMenuItem CalloutsListItem; - private static UIMenuListScrollerItem AlgorithmItem; - private static UIMenuItem TrafficControlMenuItem; - // private static UIMenuItem ConvenientToolsItem; - // private static UIMenuItem OverlayItem; - - // Language Select Menu - private static UIMenu LanguageSelectMenu; - private static UIMenuItem[] LanguageItems = new UIMenuItem[(int)Languages.Custom]; - private static UIMenuItem LanguageCustomItem; - - // Start Callouts Menu - private static UIMenu StartCalloutsListMenu; - private static UIMenuItem[] CalloutItems = new UIMenuItem[CalloutList.AllCallouts.Count]; - - // Traffic Menu - private static UIMenu TrafficControlMenu; - private static UIMenuItem PylonsItem; - // private static UIMenuItem TrafficTicketItem; - // private static UIMenuItem SpeedLimitItem; - - // Traffic Pylon Menu - internal static UIMenu PylonMenu; - private static UIMenuListScrollerItem PylonTypeItem; - internal static UIMenuCheckboxItem PylonIsFreeze; - private static UIMenuItem SetPylonPosItem; - internal static UIMenuNumericScrollerItem PylonCountItem; - private static UIMenuItem PlacePylonItem; - private static UIMenuItem ResetPylonItem; - private static UIMenuItem CarryPylonItem; - private static UIMenuListScrollerItem DeletePylonItem; - - // Speed Limit Menu - // private static UIMenu SpeedLimitMenu; - // private static UIMenuNumericScrollerItem SpeedLimitSizeItem; - // private static UIMenuItem SetSpeedLimitItem; - - // Traffic Tickets - // private static UIMenu TrafficTickets; - - // Overlay Options Menu - // private static UIMenu OverlayMenu; - // private static UIMenuItem OverlayVisibleMenuItem; - - // private static UIMenu OverlayVisibleMenu; - // private static UIMenuCheckboxItem Direction; - // private static UIMenuCheckboxItem Time; - // private static UIMenuCheckboxItem Speed; - // private static UIMenuCheckboxItem CountyName; - // private static UIMenuCheckboxItem StreetName; - - // private static UIMenu ConvenientToolsMenu; - // private static UIMenuItem GrabObjectsItem; - - // private static UIMenu GrabMenu; - // private static UIMenuItem GrabObject; - // private static UIMenuItem ReleaseObject; - // #if Dev - // private static UIMenuItem GrabVehicle; - // private static UIMenuItem ReleaseVehicle; - // #endif - - internal static void Initialize() - { - // Pool - Pool = new(); - - // Context Menu - ContextMenu = new(Translation.GetString("ContextMenuTitle"), MenuCommon.PluginInfo); - - // Language Select Menu - LanguageSelectItem = new(Translation.GetString("LanguageSelectItem"), Translation.GetString("LanguageSelectItemDesc")); - LanguageSelectMenu = new(Translation.GetString("LanguageSelectMenuTitle"), MenuCommon.PluginInfo); - for (int i = 0; i < (int)Languages.Custom; i++) - { - var lang = i; - LanguageItems[i] = new(Translation.GetString(((Languages)i).ToString().Replace("_", " ")), GetStatusText((Languages)i).ToString()); - LanguageItems[i].Activated += (m, item) => - { - Translation.SetLanguage((Languages)lang); - ClientSettings.SettingFile.Write("General", "Language", lang); - }; - } - LanguageCustomItem = new("~h~~o~Custom~s~", Translation.GetString("CustomLanguageMenuDesc")); - LanguageCustomItem.Activated += (m, i) => - { - Translation.SetLanguage(Languages.Custom); - ClientSettings.SettingFile.Write("General", "Language", (int)Languages.Custom); - }; - - LanguageSelectMenu.AddItems(LanguageItems); - LanguageSelectMenu.AddItem(LanguageCustomItem); - - // Callouts List Menu - CalloutsListItem = new(Translation.GetString("CalloutsListMenuItem"), Translation.GetString("CalloutsListMenuItemDesc")); - StartCalloutsListMenu = new(Translation.GetString("CalloutsListMenuTitle"), MenuCommon.PluginInfo); - - int j = 0; - foreach (var cl in CalloutList.AllCallouts) - { - CalloutItems[j] = new(Translation.GetString(cl.Value)); - CalloutItems[j].Activated += (m, i) => Functions.StartCallout(cl.Value); - j++; - } - StartCalloutsListMenu.AddItems(CalloutItems); - - // Algorithms Menu - AlgorithmItem = new(Translation.GetString("AlgorithmItem"), Translation.GetString("AlgorithmItemDesc"), new[] { Algorithm.SystemRandom, Algorithm.MersenneTwister, Algorithm.XorShift }); - AlgorithmItem.Activated += (m, i) => - { - RandomNumber.SetInstance(AlgorithmItem.SelectedItem); - MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("ChangeRandomNum"), Enum.GetName(typeof(Algorithm), AlgorithmItem.SelectedItem))); - ClientSettings.SettingFile.Write("General", "RandomNumberAlgorithm", (int)AlgorithmItem.SelectedItem); - }; - - // Traffic Menu - TrafficControlMenuItem = new(Translation.GetString("TrafficControlMenuItem"), Translation.GetString("TrafficControlMenuItemDesc")); - TrafficControlMenu = new(Translation.GetString("TrafficControlMenuTitle"), MenuCommon.PluginInfo); - PylonsItem = new(Translation.GetString("PylonMenuItem"), Translation.GetString("PylonMenuItemDesc")); - // SpeedLimitItem = new(Translation.GetString("SpeedLimitItem"), Translation.GetString("SpeedLimitItemDesc")); - - // Traffic Pylon Menu - PylonMenu = new(Translation.GetString("PylonMenuTitle"), MenuCommon.PluginInfo); - PylonTypeItem = new(Translation.GetString("PylonTypeItem"), Translation.GetString("PylonTypeItemDesc"), new[] { PylonType.prop_roadcone01a, PylonType.prop_roadcone01b, PylonType.prop_roadcone01c, PylonType.prop_roadcone02a, PylonType.prop_roadcone02b, PylonType.prop_roadcone02c }); - PylonTypeItem.IndexChanged += (m, oldI, newI) => - { - Pylons.SelectingPylon = PylonTypeItem.SelectedItem; - if (PylonsManager.CurrentPylons is not null) PylonsManager.CurrentPylons.UpdateGhostPylons(); - }; - PylonIsFreeze = new(Translation.GetString("PylonFreezeItem"), true, Translation.GetString("PylonFreezeItemDesc")); - SetPylonPosItem = new(Translation.GetString("StartSetPylonPos"), Translation.GetString("SetPylonPosesDesc")); - SetPylonPosItem.Activated += (m, i) => - { - switch (Pylons.status) - { - case PylonStatus.IsSetting: - SetPylonPosItem.Text = Translation.GetString("ResetPylonPos"); - Pylons.status = PylonStatus.IsSet; - Pylons.SetEndPosition(); - SetPylonPosItem.HighlightedBackColor = Color.Green; - PylonsManager.CurrentPylons = new Pylons(); - PylonsManager.CurrentPylons.ShowGhostPylons(); - PlacePylonItem.EnableItem(true); - ResetPylonItem.EnableItem(true); - if (PylonsManager.AllPylonObjects.Count is not 0) CarryPylonItem.EnableItem(true); - break; - case PylonStatus.None: - case PylonStatus.IsSet: - if (Pylons.status is PylonStatus.IsSet && Pylons.AllGhostPylons.Count > 0) PylonsManager.CurrentPylons.Reset(); - SetPylonPosItem.Text = Translation.GetString("EndSetPylonPos"); - Pylons.status = PylonStatus.IsSetting; - Pylons.SetStartPosition(); - SetPylonPosItem.HighlightedBackColor = Color.Red; - PlacePylonItem.EnableItem(false); - ResetPylonItem.EnableItem(false); - DeletePylonItem.EnableItem(false); - CarryPylonItem.EnableItem(false); - break; - } - }; - SetPylonPosItem.HighlightedBackColor = Color.Yellow; - PylonCountItem = new(Translation.GetString("PylonCountItem"), "", 1f, 19f, 1f); - PylonCountItem.Description = string.Format(Translation.GetString("PylonCountItemDesc"), PylonCountItem.Value + 1); - PylonCountItem.SliderBar = new(); - PylonCountItem.SliderBar.ForegroundColor = HudColor.Michael.GetColor(); - PylonCountItem.AllowWrapAround = false; - PylonCountItem.IndexChanged += (m, oldI, newI) => - { - PylonCountItem.Description = string.Format(Translation.GetString("PylonCountItemDesc"), PylonCountItem.Value + 1); - if (PylonsManager.CurrentPylons is not null) - { - PylonsManager.CurrentPylons.Count = PylonCountItem.Value; - PylonsManager.CurrentPylons.UpdateGhostPylons(); - } - }; - PlacePylonItem = new(Translation.GetString("PlacePylonsItem"), Translation.GetString("PlacePylonsItemDesc")); - PlacePylonItem.Activated += (m, i) => - { - if (PylonsManager.CurrentPylons is not null) - { - PylonsManager.CurrentPylons.PlacePylons(); - PylonsManager.CurrentPylons = null; - SetPylonPosItem.Text = Translation.GetString("StartSetPylonPos"); - SetPylonPosItem.HighlightedBackColor = Color.Yellow; - PlacePylonItem.EnableItem(false); - ResetPylonItem.EnableItem(false); - DeletePylonItem.EnableItem(true); - CarryPylonItem.EnableItem(true); - } - }; - PlacePylonItem.EnableItem(false); - ResetPylonItem = new(Translation.GetString("ResetPylonItem"), Translation.GetString("ResetPylonItemDesc")); - ResetPylonItem.Activated += (m, i) => - { - if (PylonsManager.CurrentPylons is not null) - { - PylonsManager.CurrentPylons.Reset(); - SetPylonPosItem.Text = Translation.GetString("StartSetPylonPos"); - SetPylonPosItem.HighlightedBackColor = Color.Yellow; - PlacePylonItem.EnableItem(false); - ResetPylonItem.EnableItem(false); - if (PylonsManager.AllPylonObjects.Count is 0) - { - DeletePylonItem.EnableItem(false); - CarryPylonItem.EnableItem(false); - } - else - { - DeletePylonItem.EnableItem(true); - CarryPylonItem.EnableItem(true); - } - } - }; - ResetPylonItem.EnableItem(false); - CarryPylonItem = new(Translation.GetString("CarryPylonItem"), Translation.GetString("CarryPylonItemDesc")); - CarryPylonItem.Activated += (m, i) => - { - PylonsManager.GrabPylon(); - if (PylonsManager.IsCarrying) - { - CarryPylonItem.Text = Translation.GetString("PlacePylonItem"); - CarryPylonItem.Description = Translation.GetString("PlacePylonItemDesc"); - } - else - { - CarryPylonItem.Text = Translation.GetString("CarryPylonItem"); - CarryPylonItem.Description = Translation.GetString("CarryPylonItemDesc"); - } - }; - CarryPylonItem.EnableItem(false); - DeletePylonItem = new(Translation.GetString("DeletePylonItem"), Translation.GetString("DeletePylonItemDesc"), new[] { Translation.GetString("NearestPylon"), Translation.GetString("AllPylon") }); - DeletePylonItem.Activated += (m, i) => - { - switch (DeletePylonItem.Index) - { - default: - case 0: - var deletePylon = PylonsManager.GetNearestPylon(PylonsManager.AllPylonObjects); - PylonsManager.AllPylonObjects.Remove(deletePylon); - if (deletePylon.Item1 && deletePylon.Item1.IsValid()) deletePylon.Item1.Delete(); - if (deletePylon.Item2 && deletePylon.Item2.IsValid()) deletePylon.Item2.Delete(); - if (PylonsManager.AllPylonObjects.Count is 0) - { - DeletePylonItem.EnableItem(false); - CarryPylonItem.EnableItem(false); - } - break; - case 1: - foreach (var p in PylonsManager.AllPylonObjects) - { - if (p.Item1 && p.Item1.IsValid()) p.Item1.Delete(); - if (p.Item2 && p.Item2.IsValid()) p.Item2.Delete(); - } - PylonsManager.AllPylonObjects.Clear(); - DeletePylonItem.EnableItem(false); - CarryPylonItem.EnableItem(false); - break; - } - }; - DeletePylonItem.EnableItem(false); - - // SpeedLimitMenu = new(Translation.GetString("SpeedLimitMenuTitle"), MenuCommon.PluginInfo); - // SpeedLimitSizeItem = new("SpeedLimitScale", "", 2f, 50f, 3f); - // SpeedLimitSizeItem.Description = string.Format(Translation.GetString("SpeedLimitScaleDescription"), SpeedLimitSizeItem.Value); - // SpeedLimitSizeItem.SliderBar = new(); - // SpeedLimitSizeItem.SliderBar.ForegroundColor = HudColor.Michael.GetColor(); - // SpeedLimitSizeItem.AllowWrapAround = true; - // SpeedLimitSizeItem.IndexChanged += (m, oldI, newI) => - // { - // SpeedLimitSizeItem.Description = string.Format(Translation.GetString("PylonCountItemDesc"), PylonCountItem.Value + 1); - // SpeedLimit.SpeedLimitScale = SpeedLimitSizeItem.Value; - // }; - - // Overlay Menu - // OverlayItem = new(Translation.GetString("OverlayOptionsItem"), Translation.GetString("OverlayOptionsItemDesc")); - // OverlayMenu = new(Translation.GetString("OverlayOptionsMenuTitle"), MenuCommon.PluginInfo); - // OverlayVisibleMenuItem = new(Translation.GetString("OverlayVisibleMenuItem"), Translation.GetString("OverlayVisibleMenuItemDesc")); - - // // Overlay Visible Menu - // OverlayVisibleMenu = new(Translation.GetString("OverlayVisibleMenuTitle"), MenuCommon.PluginInfo); - // Direction = new(Translation.GetString("OverlayDirection"), ClientSettings.Direction); - // Direction.CheckboxEvent += (m, value) => - // { - // ClientSettings.SettingFile.Write("Overlay Visible", "Direction", value); - // ClientSettings.Direction = value; - // Overlay.SwitchVisible(OverlayObjects.Direction, value); - // }; - // Time = new(Translation.GetString("OverlayTime"), ClientSettings.Time); - // Time.CheckboxEvent += (m, value) => - // { - // ClientSettings.SettingFile.Write("Overlay Visible", "Time", value); - // ClientSettings.Time = value; - // Overlay.SwitchVisible(OverlayObjects.Time, value); - // }; - // Speed = new(Translation.GetString("OverlaySpeed"), ClientSettings.Speed); - // Speed.CheckboxEvent += (m, value) => - // { - // ClientSettings.SettingFile.Write("Overlay Visible", "Speed", value); - // ClientSettings.Speed = value; - // Overlay.SwitchVisible(OverlayObjects.Speed, value); - // }; - // CountyName = new(Translation.GetString("OverlayCountyName"), ClientSettings.CountyName); - // CountyName.CheckboxEvent += (m, value) => - // { - // ClientSettings.SettingFile.Write("Overlay Visible", "CountyName", value); - // ClientSettings.CountyName = value; - // Overlay.SwitchVisible(OverlayObjects.CountyName, value); - // }; - // StreetName = new(Translation.GetString("OverlayStreetName"), ClientSettings.StreetName); - // StreetName.CheckboxEvent += (m, value) => - // { - // ClientSettings.SettingFile.Write("Overlay Visible", "StreetName", value); - // ClientSettings.StreetName = value; - // Overlay.SwitchVisible(OverlayObjects.StreetName, value); - // }; - - // Add to context menu - Pool.Add(ContextMenu, LanguageSelectMenu, StartCalloutsListMenu, TrafficControlMenu, PylonMenu); - - ContextMenu.AddItems(LanguageSelectItem, CalloutsListItem, AlgorithmItem, TrafficControlMenuItem); - ContextMenu.BindMenuToItem(LanguageSelectMenu, LanguageSelectItem); - ContextMenu.BindMenuToItem(StartCalloutsListMenu, CalloutsListItem); - ContextMenu.BindMenuToItem(TrafficControlMenu, TrafficControlMenuItem); - // ContextMenu.BindMenuToItem(OverlayMenu, OverlayItem); - - TrafficControlMenu.AddItems(PylonsItem); - TrafficControlMenu.BindMenuToItem(PylonMenu, PylonsItem); - PylonMenu.AddItems(PylonTypeItem, PylonIsFreeze, SetPylonPosItem, PylonCountItem, ResetPylonItem, PlacePylonItem, CarryPylonItem, DeletePylonItem); - - // OverlayMenu.AddItems(OverlayVisibleMenuItem); - // OverlayMenu.BindMenuToItem(OverlayVisibleMenu, OverlayVisibleMenuItem); - - // OverlayVisibleMenu.AddItems(Direction, Time, Speed, CountyName, StreetName); - - // ConvenientToolsMenu = new(Translation.GetString("ConvenientToolsMenuTitle"), MenuCommon.PluginInfo); - // GrabObjectsItem = new(Translation.GetString("GrabObjects"), Translation.GetString("GrabObjectsDesc")); - - // GrabMenu = new(Translation.GetString("GrabMenuTitle"), MenuCommon.PluginInfo); - // GrabObject = new(Translation.GetString("GrabObject"), Translation.GetString("GrabObjectDesc")); - // GrabObject.Activated += (m, i) => - // { - - // }; - - ContextMenu.MouseControlsEnabled = false; - ContextMenu.ControlDisablingEnabled = false; - LanguageSelectMenu.MouseControlsEnabled = false; - LanguageSelectMenu.ControlDisablingEnabled = false; - StartCalloutsListMenu.MouseControlsEnabled = false; - StartCalloutsListMenu.ControlDisablingEnabled = false; - TrafficControlMenu.MouseControlsEnabled = false; - TrafficControlMenu.ControlDisablingEnabled = false; - PylonMenu.MouseControlsEnabled = false; - PylonMenu.ControlDisablingEnabled = false; - // OverlayMenu.MouseControlsEnabled = false; - // OverlayMenu.ControlDisablingEnabled = false; - // OverlayVisibleMenu.MouseControlsEnabled = false; - // OverlayVisibleMenu.ControlDisablingEnabled = false; - -#if Dev - Pool.SetBannerType(Game.CreateTextureFromFile(WriteFileFromResources(Assembly.GetExecutingAssembly(), BANNER_PATH))); -#endif - Game.FrameRender += (s, e) => - { -#if Dev - Pool.DrawBanners(e.Graphics); -#endif - DynamicMenu.Process(s, e); - }; - } - - internal static void UpdateTranslate() - { - ContextMenu.TitleText = Translation.GetString("ContextMenuTitle"); - - LanguageSelectItem.Text = Translation.GetString("LanguageSelectItem"); - LanguageSelectItem.Description = Translation.GetString("LanguageSelectItemDesc"); - LanguageSelectMenu.TitleText = Translation.GetString("LanguageSelectMenuTitle"); - - CalloutsListItem.Text = Translation.GetString("CalloutsListMenuItem"); - CalloutsListItem.Description = Translation.GetString("CalloutsListMenuItemDesc"); - StartCalloutsListMenu.TitleText = Translation.GetString("CalloutsListMenuTitle"); - - AlgorithmItem.Text = Translation.GetString("AlgorithmItem"); - AlgorithmItem.Description = Translation.GetString("AlgorithmItemDesc"); - - TrafficControlMenuItem.Text = Translation.GetString("TrafficControlMenuItem"); - TrafficControlMenuItem.Description = Translation.GetString("TrafficControlMenuItemDesc"); - TrafficControlMenuItem.Text = Translation.GetString("TrafficControlMenuItem"); - TrafficControlMenuItem.Description = Translation.GetString("TrafficControlMenuItemDesc"); - TrafficControlMenu.TitleText = Translation.GetString("TrafficControlMenuTitle"); - PylonsItem.Text = Translation.GetString("PylonMenuItem"); - PylonsItem.Description = Translation.GetString("PylonMenuItemDesc"); - - PylonMenu.TitleText = Translation.GetString("PylonMenuTitle"); - PylonIsFreeze.Text = Translation.GetString("PylonFreezeItem"); - PylonIsFreeze.Description = Translation.GetString("PylonFreezeItemDesc"); - PylonTypeItem.Text = Translation.GetString("PylonTypeItem"); - PylonTypeItem.Description = Translation.GetString("PylonTypeItemDesc"); - SetPylonPosItem.Description = Translation.GetString("SetPylonPosesDesc"); - - ResetPylonItem.Text = Translation.GetString("ResetPylonItem"); - ResetPylonItem.Description = Translation.GetString("ResetPylonItemDesc"); - DeletePylonItem.Text = Translation.GetString("DeletePylonItem"); - DeletePylonItem.Description = Translation.GetString("DeletePylonItemDesc"); - DeletePylonItem.Items = new[] { Translation.GetString("NearestPylon"), Translation.GetString("AllPylon") }; - - switch (Pylons.status) - { - case PylonStatus.None: - SetPylonPosItem.Text = Translation.GetString("StartSetPylonPos"); - break; - case PylonStatus.IsSetting: - SetPylonPosItem.Text = Translation.GetString("EndSetPylonPos"); - break; - case PylonStatus.IsSet: - SetPylonPosItem.Text = Translation.GetString("ResetPylonPos"); - break; - } - - if (PylonsManager.IsCarrying) - { - CarryPylonItem.Text = Translation.GetString("PlacePylonItem"); - CarryPylonItem.Description = Translation.GetString("PlacePylonItemDesc"); - } - else - { - CarryPylonItem.Text = Translation.GetString("CarryPylonItem"); - CarryPylonItem.Description = Translation.GetString("CarryPylonItemDesc"); - } - - PylonCountItem.Text = Translation.GetString("PylonCountItem"); - PylonCountItem.Description = string.Format(Translation.GetString("PylonCountItemDesc"), PylonCountItem.Value); - PlacePylonItem.Text = Translation.GetString("PlacePylonsItem"); - PlacePylonItem.Description = Translation.GetString("PlacePylonsItemDesc"); - - for (int i = 0; i < CalloutItems.Length; i++) CalloutItems[i].Text = Translation.GetString(CalloutList.AllCallouts.ElementAt(i).Value); - for (int i = 0; i < (int)Languages.Custom; i++) LanguageItems[i].Description = GetStatusText((Languages)i).ToString(); - LanguageCustomItem.Description = Translation.GetString("CustomLanguageMenuDesc"); - } - - // internal static void SwitchVisible() - // { - - - // if (ContextMenu.Visible) ContextMenu.Visible = false; - // else if (LanguageSelectMenu.Visible) LanguageSelectMenu.Visible = false; - // else if (StartCalloutsListMenu.Visible) StartCalloutsListMenu.Visible = false; - // else if (TrafficControlMenu.Visible) TrafficControlMenu.Visible = false; - // else if (PylonMenu.Visible) PylonMenu.Visible = false; - // else if (!UIMenu.IsAnyMenuVisible) ContextMenu.Visible = true; - // } - - internal static void Process(object sender, GraphicsEventArgs e) - { - Pool.ProcessMenus(); - - if (KeyExtensions.IsKeysDown(Main.OpenContextMenuKey, Main.OpenContextMenuModifierKey)) - { - if (Pool.IsAnyMenuOpen()) - { - Pool.CloseAllMenus(); - Logger.Info("Menu Open", "DynamicLSPDFR"); - } - else if (!Pool.IsAnyMenuOpen()) - { - ContextMenu.Visible = true; - Logger.Info("Menu Open", "DynamicLSPDFR"); - } - } - } - - internal static void Reset() - { - Pool.Clear(); - Game.FrameRender -= (s, e) => - { - Pool.DrawBanners(e.Graphics); - DynamicMenu.Process(s, e); - }; - } - - internal static void EnableItem(this UIMenuItem item, bool enable) - { - if (enable) - { - item.Enabled = true; - item.HighlightedBackColor = HudColor.White.GetColor(); - } - else - { - item.Enabled = false; - item.HighlightedBackColor = HudColor.MenuGrey.GetColor(); - } - } - - private static StringBuilder GetStatusText(Languages lang) => new StringBuilder(Translation.GetString("LanguageMenuDesc")).Append("\n").Append(string.Format(Translation.GetString("TranslateStatus"), Translation.GetTranslateStatus(lang))); -} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/KeyDownUpdate.cs b/DynamicLSPDFR/Modules/KeyDownUpdate.cs index c8f7abb..2bd0a73 100644 --- a/DynamicLSPDFR/Modules/KeyDownUpdate.cs +++ b/DynamicLSPDFR/Modules/KeyDownUpdate.cs @@ -16,5 +16,6 @@ internal static void StartUpdate() internal static void KeyDownUpdate() { + if (KeyExtensions.IsKeysDown(Keys.K)) Coroner.CoronerMain(); } } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Callouts/CalloutsMenu.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Callouts/CalloutsMenu.cs new file mode 100644 index 0000000..c89e3c9 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Callouts/CalloutsMenu.cs @@ -0,0 +1,11 @@ +namespace DynamicLSPDFR.Modules.DynamicMenu; + +internal static class CalloutsMenu +{ + internal static UIMenu Callouts; + + internal static void Initialize() + { + Callouts = new(Translation.GetString("CalloutsListMenuTitle"), Main.PluginInfo); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Context.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Context.cs new file mode 100644 index 0000000..a425f54 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Context.cs @@ -0,0 +1,174 @@ +namespace DynamicLSPDFR.Modules.DynamicMenu; + +internal static class ContextMenu +{ + internal static MenuPool Pool; + internal static UIMenu Context; + private static UIMenuItem LanguageSelect; + internal static UIMenuItem CalloutsList; + private static UIMenuListScrollerItem SetAlgorithm; + private static UIMenuItem TrafficControl; + // private static UIMenuItem Overlay; + + internal static void SetupContextMenu() + { + ContextMenu.Initialize(); + CalloutsMenu.Initialize(); + ContextMenu.Initialize(); + CalloutsMenu.Initialize(); + LanguageMenu.Initialize(); + PylonsMenu.Initialize(); + TrafficMenu.Initialize(); + ContextMenu.PostfixInitialize(); + } + + internal static void Initialize() + { + Pool = new(); + Context = new(Translation.GetString("ContextMenuTitle"), Main.PluginInfo); + LanguageSelect = new(Translation.GetString("LanguageSelectItem"), Translation.GetString("LanguageSelectItemDesc")); + CalloutsList = new(Translation.GetString("CalloutsListMenuItem"), Translation.GetString("CalloutsListMenuItemDesc")); + SetAlgorithm = new(Translation.GetString("AlgorithmItem"), Translation.GetString("AlgorithmItemDesc"), new[] { Algorithm.SystemRandom, Algorithm.MersenneTwister, Algorithm.XorShift }); + SetAlgorithm.Activated += (m, i) => + { + RandomNumber.SetInstance(SetAlgorithm.SelectedItem); + MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("ChangeRandomNum"), Enum.GetName(typeof(Algorithm), SetAlgorithm.SelectedItem))); + ClientSettings.SettingFile.Write("General", "RandomNumberAlgorithm", (int)SetAlgorithm.SelectedItem); + }; + TrafficControl = new(Translation.GetString("TrafficControlMenuItem"), Translation.GetString("TrafficControlMenuItemDesc")); + // Overlay = new(Translation.GetString("OverlayMenuItem"), Translation.GetString("OverlayMenuItemDesc")); + } + + internal static void PostfixInitialize() + { + Pool.Add(Context, LanguageMenu.LanguageSelect, CalloutsMenu.Callouts, TrafficMenu.TrafficControl, PylonsMenu.PylonMenu); + + Context.AddItems(LanguageSelect, CalloutsList, SetAlgorithm, TrafficControl); + Context.BindMenuToItem(LanguageMenu.LanguageSelect, LanguageSelect); + Context.BindMenuToItem(CalloutsMenu.Callouts, CalloutsList); + Context.BindMenuToItem(TrafficMenu.TrafficControl, TrafficControl); + // Context.BindMenuToItem(OverlayMenu.Overlay, Overlay); + + TrafficMenu.TrafficControl.AddItems(TrafficMenu.Pylons); + TrafficMenu.TrafficControl.BindMenuToItem(PylonsMenu.PylonMenu, TrafficMenu.Pylons); + PylonsMenu.PylonMenu.AddItems(PylonsMenu.PylonsType, PylonsMenu.PylonIsFreeze, PylonsMenu.SetPylonPos, PylonsMenu.PylonCount, PylonsMenu.ResetPylon, PylonsMenu.PlacePylon, PylonsMenu.CarryPylon, PylonsMenu.DeletePylon); + + Context.MouseControlsEnabled = false; + Context.ControlDisablingEnabled = false; + LanguageMenu.LanguageSelect.MouseControlsEnabled = false; + LanguageMenu.LanguageSelect.ControlDisablingEnabled = false; + CalloutsMenu.Callouts.MouseControlsEnabled = false; + CalloutsMenu.Callouts.ControlDisablingEnabled = false; + TrafficMenu.TrafficControl.MouseControlsEnabled = false; + TrafficMenu.TrafficControl.ControlDisablingEnabled = false; + PylonsMenu.PylonMenu.MouseControlsEnabled = false; + PylonsMenu.PylonMenu.ControlDisablingEnabled = false; + // OverlayMenu.Overlay.MouseControlsEnabled = false; + // OverlayMenu.Overlay.ControlDisablingEnabled = false; + +#if Dev + Pool.SetBannerType(Game.CreateTextureFromFile(WriteFileFromResources(Assembly.GetExecutingAssembly(), MenuCommon.BANNER_PATH))); +#endif + Game.FrameRender += (s, e) => + { +#if Dev + Pool.DrawBanners(e.Graphics); +#endif + Process(s, e); + }; + } + + internal static void UpdateTranslate() + { + Context.TitleText = Translation.GetString("ContextMenuTitle"); + LanguageMenu.LanguageSelect.TitleText = Translation.GetString("LanguageSelectMenuTitle"); + CalloutsMenu.Callouts.TitleText = Translation.GetString("CalloutsListMenuTitle"); + TrafficMenu.TrafficControl.TitleText = Translation.GetString("TrafficControlMenuTitle"); + PylonsMenu.PylonMenu.TitleText = Translation.GetString("PylonMenuTitle"); + // OverlayMenu.Overlay.TitleText = Translation.GetString("OverlayMenuTitle"); + + LanguageSelect.Text = Translation.GetString("LanguageSelectItem"); + LanguageSelect.Description = Translation.GetString("LanguageSelectItemDesc"); + CalloutsList.Text = Translation.GetString("CalloutsListMenuItem"); + CalloutsList.Description = Translation.GetString("CalloutsListMenuItemDesc"); + SetAlgorithm.Text = Translation.GetString("AlgorithmItem"); + SetAlgorithm.Description = Translation.GetString("AlgorithmItemDesc"); + TrafficControl.Text = Translation.GetString("TrafficControlMenuItem"); + TrafficControl.Description = Translation.GetString("TrafficControlMenuItemDesc"); + TrafficMenu.Pylons.Text = Translation.GetString("PylonMenuItem"); + TrafficMenu.Pylons.Description = Translation.GetString("PylonMenuItemDesc"); + PylonsMenu.PylonIsFreeze.Text = Translation.GetString("PylonFreezeItem"); + PylonsMenu.PylonIsFreeze.Description = Translation.GetString("PylonFreezeItemDesc"); + PylonsMenu.PylonsType.Text = Translation.GetString("PylonTypeItem"); + PylonsMenu.PylonsType.Description = Translation.GetString("PylonTypeItemDesc"); + PylonsMenu.SetPylonPos.Description = Translation.GetString("SetPylonPosesDesc"); + PylonsMenu.ResetPylon.Text = Translation.GetString("ResetPylonItem"); + PylonsMenu.ResetPylon.Description = Translation.GetString("ResetPylonItemDesc"); + PylonsMenu.DeletePylon.Text = Translation.GetString("DeletePylonItem"); + PylonsMenu.DeletePylon.Description = Translation.GetString("DeletePylonItemDesc"); + PylonsMenu.DeletePylon.Items = new[] { Translation.GetString("NearestPylon"), Translation.GetString("AllPylon") }; + + switch (Pylons.status) + { + case PylonStatus.None: + PylonsMenu.SetPylonPos.Text = Translation.GetString("StartSetPylonPos"); + break; + case PylonStatus.IsSetting: + PylonsMenu.SetPylonPos.Text = Translation.GetString("EndSetPylonPos"); + break; + case PylonStatus.IsSet: + PylonsMenu.SetPylonPos.Text = Translation.GetString("ResetPylonPos"); + break; + } + + if (PylonsManager.IsCarrying) + { + PylonsMenu.CarryPylon.Text = Translation.GetString("PlacePylonItem"); + PylonsMenu.CarryPylon.Description = Translation.GetString("PlacePylonItemDesc"); + } + else + { + PylonsMenu.CarryPylon.Text = Translation.GetString("CarryPylonItem"); + PylonsMenu.CarryPylon.Description = Translation.GetString("CarryPylonItemDesc"); + } + + PylonsMenu.PylonCount.Text = Translation.GetString("PylonCountItem"); + PylonsMenu.PylonCount.Description = string.Format(Translation.GetString("PylonCountItemDesc"), PylonsMenu.PylonCount.Value); + PylonsMenu.PlacePylon.Text = Translation.GetString("PlacePylonsItem"); + PylonsMenu.PlacePylon.Description = Translation.GetString("PlacePylonsItemDesc"); + + CalloutBase.UpdateTranslate(); + for (int i = 0; i < (int)Languages.Custom; i++) LanguageMenu.AllLanguages[i].Description = MenuCommon.GetStatusText((Languages)i); + + LanguageMenu.LanguageCustom.Description = Translation.GetString("CustomLanguageMenuDesc"); + } + + internal static void Process(object sender, GraphicsEventArgs e) + { + Pool.ProcessMenus(); + + if (KeyExtensions.IsKeysDown(Main.OpenContextMenuKey, Main.OpenContextMenuModifierKey)) + { + if (Pool.IsAnyMenuOpen()) + { + Pool.CloseAllMenus(); + Logger.Info("Menu Close", "DynamicLSPDFR"); + } + else if (!Pool.IsAnyMenuOpen()) + { + Context.Visible = true; + Logger.Info("Menu Open", "DynamicLSPDFR"); + } + } + } + + internal static void Reset() + { + Pool.Clear(); + Game.FrameRender -= (s, e) => + { + Pool.DrawBanners(e.Graphics); + Process(s, e); + }; + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Language/LanguageMenu.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Language/LanguageMenu.cs new file mode 100644 index 0000000..f2c87e4 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Language/LanguageMenu.cs @@ -0,0 +1,32 @@ +namespace DynamicLSPDFR.Modules.DynamicMenu; + +internal static class LanguageMenu +{ + internal static UIMenu LanguageSelect; + internal static UIMenuItem[] AllLanguages = new UIMenuItem[(int)Languages.Custom]; + internal static UIMenuItem LanguageCustom; + + internal static void Initialize() + { + LanguageSelect = new(Translation.GetString("LanguageSelectMenuTitle"), Main.PluginInfo); + for (int i = 0; i < (int)Languages.Custom; i++) + { + var lang = i; + AllLanguages[i] = new(Translation.GetString(((Languages)i).ToString().Replace("_", " ")), MenuCommon.GetStatusText((Languages)i)); + AllLanguages[i].Activated += (m, item) => + { + Translation.SetLanguage((Languages)lang); + ClientSettings.SettingFile.Write("General", "Language", lang); + }; + } + LanguageCustom = new("~h~~o~Custom~s~", Translation.GetString("CustomLanguageMenuDesc")); + LanguageCustom.Activated += (m, i) => + { + Translation.SetLanguage(Languages.Custom); + ClientSettings.SettingFile.Write("General", "Language", (int)Languages.Custom); + }; + + LanguageSelect.AddItems(AllLanguages); + LanguageSelect.AddItem(LanguageCustom); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Overlay.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Overlay.cs new file mode 100644 index 0000000..f73d8f8 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Overlay.cs @@ -0,0 +1,14 @@ +// namespace DynamicLSPDFR.Modules.DynamicMenu; + +// internal static class OverlayMenu +// { +// internal static UIMenu Overlay; +// internal static UIMenuItem Visible; +// internal static UIMenuItem Positions; + +// internal static void Initialize() +// { +// Overlay = new(Translation.GetString("OverlayMenuTitle"), Main.PluginInfo); +// Visible = new(Translation.GetString("PylonMenuItem"), Translation.GetString("PylonMenuItemDesc")); +// } +// } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Position/Position.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Position/Position.cs new file mode 100644 index 0000000..d38a630 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Position/Position.cs @@ -0,0 +1,29 @@ +// namespace DynamicLSPDFR.Modules; + +// internal static class OverlayPositionMenu +// { +// internal static UIMenu OverlayPosition; +// internal static UIMenuListScrollerItem Item; +// internal static UIMenuNumericScrollerItem X; +// internal static UIMenuNumericScrollerItem Y; + +// internal static void Initialize() +// { +// OverlayPosition = new(Translation.GetString(""), Main.PluginInfo); +// Item = new(Translation.GetString(""), Translation.GetString(""), new[] { OverlayObjects.Direction, OverlayObjects.Time, OverlayObjects.Speed, OverlayObjects.SpeedLimit, OverlayObjects.CountyName, OverlayObjects.StreetName }); +// X = new(Translation.GetString(""), Translation.GetString(""), 0.1f, 3.0f, 0.1f); +// X.Activated += (m, i) => +// { + +// }; +// Y = new(Translation.GetString(""), Translation.GetString("")); +// Y.Activated += (m, i) => +// { + +// }; +// Item.IndexChanged += (s, oldI, newI) => +// { +// X.Index = Overlay.GetPositionOnScreen((OverlayObjects)newI).Item1; +// }; +// } +// } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Visible/Visible.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Overlay/Visible/Visible.cs new file mode 100644 index 0000000..e69de29 diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Pylons/Pylons.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Pylons/Pylons.cs new file mode 100644 index 0000000..4d1fa0c --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Pylons/Pylons.cs @@ -0,0 +1,156 @@ +namespace DynamicLSPDFR.Modules.DynamicMenu; + +internal static class PylonsMenu +{ + internal static UIMenu PylonMenu; + internal static UIMenuListScrollerItem PylonsType; + internal static UIMenuCheckboxItem PylonIsFreeze; + internal static UIMenuItem SetPylonPos; + internal static UIMenuNumericScrollerItem PylonCount; + internal static UIMenuItem PlacePylon; + internal static UIMenuItem ResetPylon; + internal static UIMenuItem CarryPylon; + internal static UIMenuListScrollerItem DeletePylon; + + internal static void Initialize() + { + PylonMenu = new(Translation.GetString("PylonMenuTitle"), Main.PluginInfo); + PylonsType = new(Translation.GetString("PylonTypeItem"), Translation.GetString("PylonTypeItemDesc"), new[] { PylonType.prop_roadcone01a, PylonType.prop_roadcone01b, PylonType.prop_roadcone01c, PylonType.prop_roadcone02a, PylonType.prop_roadcone02b, PylonType.prop_roadcone02c }); + PylonsType.IndexChanged += (m, oldI, newI) => + { + Pylons.SelectingPylon = PylonsType.SelectedItem; + if (PylonsManager.CurrentPylons is not null) PylonsManager.CurrentPylons.UpdateGhostPylons(); + }; + PylonIsFreeze = new(Translation.GetString("PylonFreezeItem"), true, Translation.GetString("PylonFreezeItemDesc")); + SetPylonPos = new(Translation.GetString("StartSetPylonPos"), Translation.GetString("SetPylonPosesDesc")); + SetPylonPos.Activated += (m, i) => + { + switch (Pylons.status) + { + case PylonStatus.IsSetting: + SetPylonPos.Text = Translation.GetString("ResetPylonPos"); + Pylons.status = PylonStatus.IsSet; + Pylons.SetEndPosition(); + SetPylonPos.HighlightedBackColor = Color.Green; + PylonsManager.CurrentPylons = new Pylons(); + PylonsManager.CurrentPylons.ShowGhostPylons(); + PlacePylon.EnableItem(true); + ResetPylon.EnableItem(true); + if (PylonsManager.AllPylonObjects.Count is not 0) CarryPylon.EnableItem(true); + break; + case PylonStatus.None: + case PylonStatus.IsSet: + if (Pylons.status is PylonStatus.IsSet && Pylons.AllGhostPylons.Count > 0) PylonsManager.CurrentPylons.Reset(); + SetPylonPos.Text = Translation.GetString("EndSetPylonPos"); + Pylons.status = PylonStatus.IsSetting; + Pylons.SetStartPosition(); + SetPylonPos.HighlightedBackColor = Color.Red; + PlacePylon.EnableItem(false); + ResetPylon.EnableItem(false); + DeletePylon.EnableItem(false); + CarryPylon.EnableItem(false); + break; + } + }; + SetPylonPos.HighlightedBackColor = Color.Yellow; + PylonCount = new(Translation.GetString("PylonCount"), "", 1f, 19f, 1f); + PylonCount.Description = string.Format(Translation.GetString("PylonCountDesc"), PylonCount.Value + 1); + PylonCount.SliderBar = new(); + PylonCount.SliderBar.ForegroundColor = HudColor.Michael.GetColor(); + PylonCount.AllowWrapAround = false; + PylonCount.IndexChanged += (m, oldI, newI) => + { + PylonCount.Description = string.Format(Translation.GetString("PylonCountDesc"), PylonCount.Value + 1); + if (PylonsManager.CurrentPylons is not null) + { + PylonsManager.CurrentPylons.Count = PylonCount.Value; + PylonsManager.CurrentPylons.UpdateGhostPylons(); + } + }; + PlacePylon = new(Translation.GetString("PlacePylonsItem"), Translation.GetString("PlacePylonsItemDesc")); + PlacePylon.Activated += (m, i) => + { + if (PylonsManager.CurrentPylons is not null) + { + PylonsManager.CurrentPylons.PlacePylons(); + PylonsManager.CurrentPylons = null; + SetPylonPos.Text = Translation.GetString("StartSetPylonPos"); + SetPylonPos.HighlightedBackColor = Color.Yellow; + PlacePylon.EnableItem(false); + ResetPylon.EnableItem(false); + DeletePylon.EnableItem(true); + CarryPylon.EnableItem(true); + } + }; + PlacePylon.EnableItem(false); + ResetPylon = new(Translation.GetString("ResetPylon"), Translation.GetString("ResetPylonDesc")); + ResetPylon.Activated += (m, i) => + { + if (PylonsManager.CurrentPylons is not null) + { + PylonsManager.CurrentPylons.Reset(); + SetPylonPos.Text = Translation.GetString("StartSetPylonPos"); + SetPylonPos.HighlightedBackColor = Color.Yellow; + PlacePylon.EnableItem(false); + ResetPylon.EnableItem(false); + if (PylonsManager.AllPylonObjects.Count is 0) + { + DeletePylon.EnableItem(false); + CarryPylon.EnableItem(false); + } + else + { + DeletePylon.EnableItem(true); + CarryPylon.EnableItem(true); + } + } + }; + ResetPylon.EnableItem(false); + CarryPylon = new(Translation.GetString("CarryPylon"), Translation.GetString("CarryPylonDesc")); + CarryPylon.Activated += (m, i) => + { + PylonsManager.GrabPylon(); + if (PylonsManager.IsCarrying) + { + CarryPylon.Text = Translation.GetString("PlacePylon"); + CarryPylon.Description = Translation.GetString("PlacePylonDesc"); + } + else + { + CarryPylon.Text = Translation.GetString("CarryPylon"); + CarryPylon.Description = Translation.GetString("CarryPylonDesc"); + } + }; + CarryPylon.EnableItem(false); + DeletePylon = new(Translation.GetString("DeletePylon"), Translation.GetString("DeletePylonDesc"), new[] { Translation.GetString("NearestPylon"), Translation.GetString("AllPylon") }); + DeletePylon.Activated += (m, i) => + { + switch (DeletePylon.Index) + { + default: + case 0: + var deletePylon = PylonsManager.GetNearestPylon(PylonsManager.AllPylonObjects); + PylonsManager.AllPylonObjects.Remove(deletePylon); + if (deletePylon.Item1 && deletePylon.Item1.IsValid()) deletePylon.Item1.Delete(); + if (deletePylon.Item2 && deletePylon.Item2.IsValid()) deletePylon.Item2.Delete(); + if (PylonsManager.AllPylonObjects.Count is 0) + { + DeletePylon.EnableItem(false); + CarryPylon.EnableItem(false); + } + break; + case 1: + foreach (var p in PylonsManager.AllPylonObjects) + { + if (p.Item1 && p.Item1.IsValid()) p.Item1.Delete(); + if (p.Item2 && p.Item2.IsValid()) p.Item2.Delete(); + } + PylonsManager.AllPylonObjects.Clear(); + DeletePylon.EnableItem(false); + CarryPylon.EnableItem(false); + break; + } + }; + DeletePylon.EnableItem(false); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Traffic.cs b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Traffic.cs new file mode 100644 index 0000000..e39e769 --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/DynamicMenu/Traffic/Traffic.cs @@ -0,0 +1,13 @@ +namespace DynamicLSPDFR.Modules.DynamicMenu; + +internal static class TrafficMenu +{ + internal static UIMenu TrafficControl; + internal static UIMenuItem Pylons; + + internal static void Initialize() + { + TrafficControl = new(Translation.GetString("TrafficControlMenuTitle"), Main.PluginInfo); + Pylons = new(Translation.GetString("PylonMenuItem"), Translation.GetString("PylonMenuItemDesc")); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Menues/TrafficTickets/TrafficTickets.cs b/DynamicLSPDFR/Modules/Menues/TrafficTickets/TrafficTickets.cs new file mode 100644 index 0000000..7732f1a --- /dev/null +++ b/DynamicLSPDFR/Modules/Menues/TrafficTickets/TrafficTickets.cs @@ -0,0 +1,8 @@ +// namespace DynamicLSPDFR.Modules; + +// internal static class TrafficTicketsMenu +// { +// private static UIMenu TicketMenu; +// private static UIMenuListItem FineItem; +// private static List FineList = new(); +// } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Overlay.cs b/DynamicLSPDFR/Modules/Overlay.cs index 20fea02..931537f 100644 --- a/DynamicLSPDFR/Modules/Overlay.cs +++ b/DynamicLSPDFR/Modules/Overlay.cs @@ -5,22 +5,21 @@ // Direction, // Time, // Speed, +// SpeedLimit, // CountyName, // StreetName, // } // internal static class Overlay // { -// internal static ResRectangle directionBackground, timeBackground, speedBackground, countyBackground, streetBackground; -// internal static ResText directionText, timeText, speedText, countyText, streetText; +// internal static ResText directionText, timeText, speedText, speedLimitText, countyText, streetText; // internal static void Initialize() // { // var screen = UIMenu.GetScreenResolutionMantainRatio(); -// directionBackground = new(new(351, (int)(screen.Height - 125)), new(180, 70), Color.FromArgb(200, Color.Black)); // directionText = new("", new(438, (int)(screen.Height - 125)), 1f, Color.White, EFont.ChaletLondon, ResText.Alignment.Centered); -// timeBackground = new(new()); +// // timeBackground = new(new()); // Game.FrameRender += GameOnFrameRender; // } @@ -30,13 +29,33 @@ // switch (obj) // { // case OverlayObjects.Direction: -// directionBackground.Enabled = visible; // directionText.Enabled = visible; // break; // case OverlayObjects.Time: // break; // case OverlayObjects.Speed: // break; +// case OverlayObjects.SpeedLimit: +// break; +// case OverlayObjects.CountyName: +// break; +// case OverlayObjects.StreetName: +// break; +// } +// } + +// internal static void UpdatePosAndSize(OverlayObjects obj) +// { +// switch (obj) +// { +// case OverlayObjects.Direction: +// break; +// case OverlayObjects.Time: +// break; +// case OverlayObjects.Speed: +// break; +// case OverlayObjects.SpeedLimit: +// break; // case OverlayObjects.CountyName: // break; // case OverlayObjects.StreetName: @@ -44,13 +63,26 @@ // } // } +// internal static (float, float) GetPositionOnScreen(OverlayObjects obj) +// { +// switch (obj) +// { +// case OverlayObjects.Direction: return (directionText.Position.X, directionText.Position.Y); +// case OverlayObjects.Time: return (timeText.Position.X, timeText.Position.Y); +// case OverlayObjects.Speed: return (speedText.Position.X, speedText.Position.Y); +// case OverlayObjects.SpeedLimit: return (speedLimitText.Position.X, speedLimitText.Position.Y); +// case OverlayObjects.CountyName: return (countyText.Position.X, countyText.Position.Y); +// case OverlayObjects.StreetName: return (streetText.Position.X, streetText.Position.Y); +// default: return (0f, 0f); +// } +// } + // private static void GameOnFrameRender(object sender, GraphicsEventArgs e) // { -// directionBackground.Draw(); // directionText.Draw(); // if (HeadingExtensions.GetPedDirection(Game.LocalPlayer.Character) is Directions.Unknown) directionText.Caption = "Unknown"; -// else directionText.Caption = Translation.GetString(HeadingExtensions.GetPedDirection(Game.LocalPlayer.Character).ToString()); +// else directionText.Caption = HeadingExtensions.GetPedDirection(Game.LocalPlayer.Character).ToString(); // // headingText.Caption = HeadingExtensions.GetPedDirection(Game.LocalPlayer.Character).ToString(); // } // } \ No newline at end of file diff --git a/DynamicLSPDFR/Modules/Pylons.cs b/DynamicLSPDFR/Modules/Pylons.cs index 92b0bb3..1476359 100644 --- a/DynamicLSPDFR/Modules/Pylons.cs +++ b/DynamicLSPDFR/Modules/Pylons.cs @@ -59,7 +59,7 @@ internal static void GrabPylon() var pos = Game.LocalPlayer.Character.GetOffsetPositionFront(1f); grabbingPylon.Item1.Position = new(pos.X, pos.Y, (float)World.GetGroundZ(pos, true, true)); grabbingPylon.Item1.Rotation = grabbingPylonRotatorCache; - grabbingPylon.Item1.IsPositionFrozen = DynamicMenu.PylonIsFreeze.Checked; + grabbingPylon.Item1.IsPositionFrozen = DynamicMenu.PylonsMenu.PylonIsFreeze.Checked; grabbingPylon.Item1.IsCollisionEnabled = true; if (grabbingPylon.Item2 && grabbingPylon.Item2.IsValid()) { @@ -112,7 +112,7 @@ internal class Pylons internal static Vector3 startPos = Vector3.Zero, endPos = Vector3.Zero; internal static PylonStatus status = PylonStatus.None; internal static Object StartMarker, EndMarker; - internal float Count = DynamicMenu.PylonCountItem.Value; + internal float Count = DynamicMenu.PylonsMenu.PylonCount.Value; internal Pylons() { } @@ -158,9 +158,9 @@ internal void PlacePylons() if (p) { p.Opacity = 1f; - p.IsPositionFrozen = DynamicMenu.PylonIsFreeze.Checked; + p.IsPositionFrozen = DynamicMenu.PylonsMenu.PylonIsFreeze.Checked; p.IsCollisionEnabled = true; - if (DynamicMenu.PylonIsFreeze.Checked) + if (DynamicMenu.PylonsMenu.PylonIsFreeze.Checked) { ghostPed = new(p.Position); if (ghostPed && ghostPed.IsValid()) diff --git a/DynamicLSPDFR/Modules/TrafficTickets.cs b/DynamicLSPDFR/Modules/TrafficTickets.cs new file mode 100644 index 0000000..ff7c85e --- /dev/null +++ b/DynamicLSPDFR/Modules/TrafficTickets.cs @@ -0,0 +1,50 @@ +// namespace DynamicLSPDFR.Modules; + +// internal class TrafficTickets +// { +// internal string Name { get; set; } = "[NoName]"; +// internal string Category { get; set; } = "[NoCategory]"; +// internal int Points { get; set; } = 0; +// internal int Fine { get; set; } = 5; + +// internal const string XML_FILES_DIRECTORY = @"plugins/LSPDFR/DynamicLSPDFR/"; +// internal static int LimitOfSeize { get; set; } = 10; +// internal static bool SeizeVehicle { get; set; } = false; +// internal static string Unit { get; set; } = "$"; +// internal static bool RightUnitPosition { get; set; } = false; +// internal static Dictionary> AllTrafficTicketCategories { get; set; } = new(); + +// internal static List LoadTickets() +// { +// List AllTrafficTickets = new(); +// if (Directory.Exists(XML_FILES_DIRECTORY)) +// { +// foreach (string file in Directory.EnumerateFiles(XML_FILES_DIRECTORY, "*.xml", SearchOption.TopDirectoryOnly)) +// { +// try +// { +// using (var reader = new StreamReader(file)) +// { +// XmlSerializer deserializer = new(typeof(List), +// new XmlRootAttribute("Tickets")); +// AllTrafficTickets.AddRange((List)deserializer.Deserialize(reader)); +// } +// } +// catch (Exception e) +// { +// Logger.ErrorCode("Traffic Tickets", 30); +// Logger.Error(e.ToString(), "Traffic Tickets"); +// } +// } +// } + +// if (AllTrafficTickets.Count is 0) +// { +// AllTrafficTickets.Add(new TrafficTickets()); +// MessageExtensions.SendMessageInGame(Translation.GetString("NoTickets")); +// } + +// AllTrafficTicketCategories = AllTrafficTickets.GroupBy(x => x.Category).ToDictionary(x => x.Key, x => x.ToList()); +// return AllTrafficTickets; +// } +// } \ No newline at end of file diff --git a/DynamicLSPDFR/Properties/AssemblyInfo.cs b/DynamicLSPDFR/Properties/AssemblyInfo.cs index 1a5e6ef..cf38bbc 100644 --- a/DynamicLSPDFR/Properties/AssemblyInfo.cs +++ b/DynamicLSPDFR/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます // 既定値にすることができます: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.2.0.1")] -[assembly: AssemblyFileVersion("0.2.0.1")] +[assembly: AssemblyVersion("0.3.0.0")] +[assembly: AssemblyFileVersion("0.3.0.0")] diff --git a/DynamicLSPDFR/Resources/Readme/Japanese.txt b/DynamicLSPDFR/Resources/Readme/Japanese.txt index f7260fc..674bd55 100644 --- a/DynamicLSPDFR/Resources/Readme/Japanese.txt +++ b/DynamicLSPDFR/Resources/Readme/Japanese.txt @@ -5,7 +5,7 @@ -------------------インストール方法------------------ 1. Zipファイルをダウンロードします。 -2. 解答して中身のGrandTheftAutoVフォルダを開きます。 +2. 解凍して中身のGrandTheftAutoVフォルダを開きます。 3. 中にある「LSPDFR」、「Plugins」、「RAGENativeUI.dll」をすべてGTA5.exeがあるディレクトリに移動もしくはコピーします。 4. RAGEPluginHookでゲームを起動してください ---------------------------------------------------- diff --git a/DynamicLSPDFR/Resources/Translate.json b/DynamicLSPDFR/Resources/Translate.json index ff90578..75686e2 100644 --- a/DynamicLSPDFR/Resources/Translate.json +++ b/DynamicLSPDFR/Resources/Translate.json @@ -5,7 +5,8 @@ "3": "~b~{0}~s~ was successfully loaded!\n~g~Thank you for playing!~s~", "5": "{0} wurde erfolgreich geladen!", "6": "{0} \u00e8 stato caricato correttamente!\nGrazie per aver giocato!", - "8": "{0} zosta\u0142o pomy\u015blnie wczytane!\nDzi\u0119ki za zagranie!", + "8": "~b~{0}~s~ zosta\u0142o pomy\u015blnie wczytane!\n~g~Dzi\u0119ki za zagranie!~s~", + "9": "~b~{0}~s~ Carregou com sucesso!\n~g~Obrigado por jogar!~s~", "10": "~b~{0}~s~ was successfully loaded!\n~g~Thank you for playing!~s~", "11": "\u00a1{0} se ha cargado exitosamente!\n\u00a1Gracias por jugar!", "12": "\u00a1{0} se ha cargado exitosamente!\n\u00a1Gracias por jugar!", @@ -25,6 +26,7 @@ "5": "Du kannst jetzt einen Einsatz erhalten.", "6": "Ricevi chiamata", "8": "Mo\u017cesz ju\u017c otrzyma\u0107 kolejne zg\u0142oszenie.", + "9": "~g~Voc\u00ea pode receber chamados agora.~s~", "10": "~g~You can receive callout now.~s~", "11": "Ahora puedes recibir llamadas.", "12": "Ahora puedes recibir llamadas.", @@ -44,6 +46,7 @@ "5": "Du kannst gerade keine Eins\u00e4tze erhalten.", "6": "Non Ricevere chiamata", "8": "Nie dostaniesz teraz \u017cadnego zg\u0142oszenia.", + "9": "~y~Voc\u00ea n\u00e3o pode receber chamados agora.~s~", "10": "~y~Any callouts can't receive you now.~s~", "11": "No recibir\u00e1s ninguna llamada ahora", "12": "No recibir\u00e1s ninguna llamada ahora.", @@ -58,9 +61,11 @@ "0": "\u8a00\u8a9e\u304c~b~\u65e5\u672c\u8a9e~s~\u306b\u8a2d\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002", "2": "\u73fe\u5728\u8a2d\u5b9a\u7684\u8a9e\u8a00\u70ba ~b~ \u7e41\u9ad4\u4e2d\u6587\uff08\u53f0\u7063\uff09 ~s~ \u3002", "3": "The Language is now ~b~English~s~.", + "4": "R\u00e9gler langue", "5": "Die Sprache ist jetzt Deutsch", "6": "La lingua \u00e8 ora Italiano", "8": "Ustawiony j\u0119zyk to Polski", + "9": "O idioma agora \u00e9 ~b~Portugu\u00eas Brasileiro~s~.", "10": "The Language is now ~b~English~s~.", "11": "Idioma actual es el espa\u00f1ol", "12": "Idioma actual es el espa\u00f1ol latin america.", @@ -79,6 +84,7 @@ "5": "~g~Code 4~s~.\nBitte gehe weiter auf Streife.", "6": "Siamo ~g~Codice 4~s~.\n Per favore, continua la tua pattuglia.", "8": "Zg\u0142oszenie zosta\u0142o ~g~zako\u0144czone~s~.\nKontynuuj sw\u00f3j patrol.", + "9": "Estamos em ~g~C\u00f3digo 4~s~.\nContinue a patrulha.", "10": "We're ~g~Code 4~s~.\nPlease continue your patrol.", "11": "Llamada ha ~g~terminado~s~\nPor favor, contin\u00faa tu patrulla.", "12": "Estamos~g~C\u00f3digo 4~s~\nPor favor, contin\u00fae su patrulla.", @@ -98,6 +104,7 @@ "5": "Zentrale", "6": "Segnalazione", "8": "00", + "9": "Central", "10": "\u0414\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440", "11": "Despacho", "12": "Despacho", @@ -111,10 +118,11 @@ "UpdateMessage": { "0": "~b~{0}~s~\u306e~y~\u6700\u65b0\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8~s~\u304c\u3042\u308a\u307e\u3059\u3002\n~r~\u65e9\u6025\u306b\u66f4\u65b0\u3057\u3066\u304f\u3060\u3055\u3044\u3002~s~", "2": "{0} \u6709~y~ \u6700\u65b0\u7248\u672c ~s~ \uff0c\n~r~ \u8acb\u66f4\u65b0\u6b64\u63d2\u4ef6 ~s~ \u3002", - "3": "~b~{0}~s~ has ~y~a newer update~s~. ~r~Please update this plugin!~s~", + "3": "~b~{0}~s~ has ~y~a newer update~s~.\n~r~Please update this plugin!~s~", "5": "{0} Hat ein neues Update.\nBitte update dein Plugin.", "6": "{0} rilasciato nuovo aggiornamento.\n Si prega di aggiornare questo plugin.", "8": "{0} ma nowsz\u0105 wersj\u0119.\nProsz\u0119, zaktualizuj ten plugin.", + "9": "{0} existe uma nova atualiza\u00e7\u00e3o.\nPor favor, atualize o plugin.", "10": "~b~{0}~s~ has ~y~a newer update~s~. ~r~Please update this plugin!~s~", "11": "{0} tiene una \u00faltima actualizaci\u00f3n.\nPor favor, actualiza este plugin.", "12": "{0} tiene la \u00faltima actualizaci\u00f3n.\nPor favor, actualice este plugin.", @@ -134,6 +142,7 @@ "5": "Update erh\u00e4ltlich!", "6": "Aggiornamento disponibile", "8": "Dost\u0119pna aktualizacja!", + "9": "Atualiza\u00e7\u00e3o Dispon\u00edvel", "10": "\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435", "11": "\u00a1Actualizaci\u00f3n disponible!", "12": "\u00a1Actualizaci\u00f3n disponible!", @@ -144,6 +153,10 @@ "19": "P\u00e4ivitys saatavilla!", "20": "I\u0161leistas atnaujinimas!" }, + "UpdateVersion": { + "0": "~r~\u4eca\u306e\u30d0\u30fc\u30b8\u30e7\u30f3~s~: {0}\n~g~\u6700\u65b0\u7248\u306e\u30d0\u30fc\u30b8\u30e7\u30f3~s~: {1}", + "3": "~r~Current Version~s~: {0}\n~g~Latest Version~s~: {1}" + }, "ChangeRandomNum": { "0": "\u4e71\u6570\u751f\u6210\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u304c~o~{0}~s~\u306b\u8a2d\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002", "2": "\u96a8\u6a5f\u6578\u751f\u6210\u7b97\u6cd5\u5df2\u8a2d\u7f6e\u70ba ~o~ {0} ~s~ \u3002", @@ -151,6 +164,7 @@ "5": "Der Zufallszahlenalgorithmus wurde zu {0} gesetzt.", "6": "L'algoritmo del numero casuale \u00e8 stato impostato su {0}.", "8": "Algorytm losowych liczb zosta\u0142 ustawiony na {0}.", + "9": "O algoritmo aleat\u00f3rio foi setado para ~o~{0}~s~.", "10": "The Random Number Algorithm was set to ~o~{0}~s~.", "11": "El algoritmo de n\u00fameros aleatorios se configur\u00f3 en {0}.", "12": "El algoritmo de n\u00fameros aleatorios se configur\u00f3 en {0}.", @@ -169,6 +183,7 @@ "5": "Konversation", "6": "Conversazione", "8": "Konwersacja", + "9": "Conversa", "10": "\u041e\u0431\u0449\u0435\u043d\u0438\u0435 ", "11": "Conversaci\u00f3n", "12": "Conversacion", @@ -187,6 +202,7 @@ "5": "W\u00e4hle Antwort aus", "6": "Seleziona la risposta", "8": "Wybierz odpowied\u017a.", + "9": "Escolha a Resposta", "10": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0442\u0432\u0435\u0442", "11": "Eleg\u00ed una respuesta", "13": "~g~Cevab\u0131~s~ se\u00e7", @@ -204,6 +220,7 @@ "5": "Verhafte den ~r~Verd\u00e4chtigen~s~.", "6": "Arresta il sospetto", "8": "Zaaresztuj ~r~Podejrzanego~s~.", + "9": "Prenda o ~r~Suspeito~s~.", "10": "\u0410\u0440\u0435\u0441\u0442\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0435\u043c\u043e\u0433\u043e", "11": "Arresta un sospechoso", "13": "~r~\u015e\u00fcpheliyi~s~ ~y~tutukla~s~.", @@ -217,8 +234,11 @@ "0": "~h~~r~\u30a8\u30e9\u30fc~s~~h~\n\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3068\u306e\u8ddd\u96e2\u304c\u9060\u3059\u304e\u307e\u3059\u3002", "2": "~h~~r~ \u932f\u8aa4 ~s~~h~\n\u4f60\u96e2\u76ee\u6a19\u592a\u9060\u3002", "3": "~h~~r~Error~s~~h~\nYou're too far away from the object.", + "4": "Erreur trop loin", + "5": "~h~~r~Fehler~s~~h~\nDu bist von dem Objekt zu weit entfernt.", "6": "Errore\n Sei troppo lontano dall'oggetto.", "8": "~h~~r~B\u0142\u0105d~s~~h~\nJeste\u015b zbyt daleko od obiektu.", + "9": "~h~~r~Erro~s~~h~\nVoc\u00ea est\u00e1 muito longe do objeto.", "10": "~h~~r~\u041e\u0448\u0438\u0431\u043a\u0430~s~~h~\n\u0412\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0435\u0441\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0434\u0430\u043b\u0435\u043a\u043e \u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u0430.", "11": "~h~~r~Error~s~~h~\nEst\u00e1s demasiado lejos del objeto.", "13": "~h~~r~Hata~s~~h~\nHedeften uzaks\u0131n\u0131z.", @@ -226,6 +246,833 @@ "16": "~h~~r~Error~s~~h~\nDu \u00e4r f\u00f6r l\u00e5ngt ifr\u00e5n objektet.", "20": "~h~~r~Klaida~s~~h~\nJ\u016bs per daug nutole nuo objekto." }, + "Robber": { + "0": "\u5f37\u76d7\u72af", + "2": "\u6436\u532a", + "3": "Robber", + "4": "Braquage en cours", + "5": "R\u00e4uber", + "6": "Rapina", + "8": "Z\u0142odziej", + "9": "Ladr\u00e3o", + "10": "\u0413\u0440\u0430\u0431\u0438\u0442\u0435\u043b\u044c", + "13": "H\u0131rs\u0131z", + "14": "Lupic", + "16": "R\u00e5nare", + "20": "Vagis" + }, + "RobbedBank": { + "0": "\u5f37\u76d7\u3055\u308c\u3066\u3044\u308b\u9280\u884c", + "2": "\u9280\u884c\u88ab\u6436\u52ab", + "3": "Robbed Bank", + "4": "Banque braqu\u00e9e", + "5": "Ausgeraubte Bank", + "6": "Rapina in banca", + "8": "Okradziony bank", + "9": "Banco Roubado", + "10": "\u041e\u0433\u0440\u0430\u0431\u043b\u0435\u043d\u043d\u044b\u0439 \u0431\u0430\u043d\u043a", + "13": "Ya\u011fmalanm\u0131\u015f Banka", + "14": "Vyloupena banka", + "16": "R\u00e5nade Banken", + "20": "Apvogtas bankas" + }, + "SearchArea": { + "0": "\u635c\u7d22\u7bc4\u56f2", + "2": "\u641c\u5c0b\u5340\u57df", + "3": "Search Area", + "4": "Zone de recherche", + "5": "Suchgebiet", + "6": "Zona di ricerca", + "8": "Przeszukaj obszar", + "9": "Per\u00edmetro de Busca", + "10": "\u041e\u0431\u043b\u0430\u0441\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u0430", + "13": "Etraf\u0131 ara", + "14": "Oblast pro hledani", + "16": "S\u00f6komr\u00e5de", + "20": "Ie\u0161kojimo perimetras" + }, + "SuspectArea": { + "0": "\u88ab\u7591\u8005\u306e\u9003\u8d70\u7bc4\u56f2", + "2": "\u5acc\u72af\u53ef\u80fd\u7684\u9003\u96e2\u5340\u57df", + "3": "Range of the suspect's escape", + "4": "Zone suspecte", + "5": "Aufenthaltsort des T\u00e4ters", + "6": "Zona sospetta", + "8": "Zasi\u0119g ucieczki podejrzanego", + "9": "Per\u00edmetro de fuga do suspeito", + "10": "\u041f\u043e\u0434\u043e\u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c", + "13": "\u015e\u00fcphelinin ka\u00e7mas\u0131na kalan mesafe", + "14": "Rozsah uteku podezreleho", + "16": "Misst\u00e4nkt Omr\u00e5de", + "20": "\u012etariamojo b\u0117gimo perimetras" + }, + "SuspectSearching": { + "0": "\u5831\u544a\u3055\u308c\u305f\u60c5\u5831\u3092\u57fa\u306b\u8eca\u4e21\u3092\u7279\u5b9a\u4e2d\u3002", + "2": "\u6b63\u6839\u64da\u4e0a\u5831\u7684\u8cc7\u6599\u9032\u884c\u8eca\u8f1b\u8fa8\u8b58", + "3": "The vehicle is being identified based on the reported information.", + "4": "Recherche du suspect", + "5": "Das Fahrzeug wird mit der angegebenen Beschreibung gesucht.", + "6": "Il veicolo \u00e8 stato identificato sulla base delle informazioni riportate.", + "8": "Trwa identyfikacja pojazdu na podstawie zg\u0142oszonych informacji.", + "9": "O ve\u00edculo est\u00e1 identificado conforme a informa\u00e7\u00e3o reportada.", + "10": "\u041f\u043e\u0438\u0441\u043a \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0435\u043c\u043e\u0433\u043e", + "13": "Rapor edilen bilgilere g\u00f6re arac\u0131n kimli\u011fi belirleniyor...", + "14": "Vozidlo bylo identifikovano na zaklade nahlasenych informaci.", + "16": "Fordonet har identifieras baserat p\u00e5 inrapporterad information.", + "20": "The vehicle is being identified based on the reported information.\nAutomobilis \u0161iuo metu yra nustatomas pagal duot\u0105 informacij\u0105" + }, + "SuspectLocation": { + "0": "~r~\u88ab\u7591\u8005~s~\u306e\u4f4d\u7f6e\u3092\u7279\u5b9a\u3002\n\u73fe\u5728~y~{0}~s~\u3092~b~{1}~s~\u306b\u9003\u8d70\u4e2d\u3002", + "2": "~r~\u5acc\u72af~s~\u5df2\u88ab\u5b9a\u4f4d\n\u76ee\u524d\u5728 ~y~{0}~s~ \u5f80 ~b~{1}~s~\u65b9\u5411\u9003\u9038\u3002", + "3": "~r~Suspect~s~ located.\nCurrently, fleeing ~y~{0}~s~ to ~b~{1}~s~.", + "4": "Localisation du suspect", + "5": "~r~T\u00e4ter~s~ gefunden!\nEr flieht~y~{0}~s~ Richtung ~b~{1}~s~.", + "6": "~r~Sospetto~s~ individuato.\n Attualmente, in fuga da ~y~{0}~s~ verso ~b~{1}~s~.", + "8": "~r~Podejrzany~s~ zlokalizowany.\nObecnie ucieka ~y~{0}~s~ do ~b~{1}~s~.", + "9": "~r~Suspeito~s~ localizado.\nAtualmente, fugindo ~y~{0}~s~ pata ~b~{1}~s~.", + "10": "\u041f\u043e\u0434\u043e\u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435", + "13": "~r~\u015e\u00fcpheli~s~ tespit edildi.\n\u015euan, ~y~{0}~s~ y\u00f6n\u00fcnden ~b~{1}~s~ y\u00f6n\u00fcne do\u011fru ka\u00e7\u0131yor.", + "14": "~r~Podezrely~s~ nalezen. V soucasne dobe utika z ~y~{0}~s~ do ~b~{1}~s~.", + "16": "~r~G\u00e4rningsmannen~s~ lokaliserad.\nJust nu flyr han ~y~{0}~s~ mot ~b~{1}~s~.", + "20": "~r~\u012etariamasis~s~ surastas\n\u0160iuo metu, sprunka nuo ~y~{0}~s~ iki ~b~{1}~s~" + }, + "SuspectReport": { + "0": "\u3042\u306a\u305f: ~r~\u88ab\u7591\u8005\u306e\u8eca\u4e21~s~\u306e\u30ca\u30f3\u30d0\u30fc\u306f~b~{0}~s~\u3067\u8272\u306f~b~{1}~s~\u3067\u3059\u3002", + "2": "\u4f60\uff1a ~r~\u5acc\u72af\u8eca\u8f1b~s~ \u8eca\u724c\u865f\u78bc\u70ba ~b~{0}~s~ \uff0c\u8eca\u8eab\u9854\u8272~b~{1}~s~\u3002", + "3": "You: ~r~The suspect vehicle's~s~ license plate number is ~b~{0}~s~ and its color is ~b~{1}~s~.", + "4": "Suspect rapport\u00e9", + "5": "Du: ~r~Das Kennzeichen von dem T\u00e4ter~s~ lautet ~b~{0}~s~, und die Fahrzeugfarbe ist ~b~{1}~s~.", + "6": "Tu: ~r~Il numero di targa~s~ del veicolo sospetto \u00e8 ~b~{0}~s~ e il suo colore \u00e8 ~b~{1}~s~.", + "8": "Ty: Numer rejestracyjny ~r~podejrzanego pojazdu~s~ to ~b~{0}~s~, a jego kolor to ~b~{1}~s~.", + "9": "Voc\u00ea ~s~A placa do carro do~r~ suspeito \u00e9 ~b~{0}~s~ e a cor \u00e9 ~b~{1}~s~.", + "10": "\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0435\u043c\u043e\u043c", + "13": "Sen: ~r~\u015e\u00fcpheli arac\u0131n plakas\u0131~s~ ~b~{0}~s~, rengi ise ~b~{1}~s~.", + "14": "Vy: ~r~SPZTKA podezreleho vozidla~s~ je ~b~{0}~s~ a jeho barva je ~b~{1}~s~.", + "16": "Du: ~r~G\u00e4rningsmannens fordon's~s~ registrerings nummer \u00e4r ~b~{0}~s~ och har f\u00e4rgen ~b~{1}~s~.", + "20": "Tu: ~r~\u012etariamojo automobilio~s~ valstybinis numeris yra ~b~{0}~s~, automobilio spalva ~b~{1}~s~" + }, + "N": { + "0": "\u5317", + "2": "\u5317", + "3": "N", + "4": "N", + "5": "N", + "6": "N", + "8": "N", + "9": "N", + "10": "N", + "13": "K", + "14": "S", + "16": "Norr", + "20": "\u0160" + }, + "NNE": { + "0": "\u5317\u5317\u897f", + "2": "\u6771\u5317\u504f\u5317", + "3": "NNE", + "4": "N-N-E", + "5": "NNE", + "6": "NNE", + "8": "NNE", + "9": "NNE", + "10": "NNE", + "13": "KKD", + "14": "SSV", + "16": "Nord-Nordost", + "20": "\u0160\u0160R" + }, + "NE": { + "0": "\u5317\u897f", + "2": "\u6771\u5317", + "3": "NE", + "4": "N-E", + "5": "NE", + "6": "Ne", + "8": "NE", + "9": "NE", + "10": "NE", + "13": "KD", + "14": "SV", + "16": "Nordost", + "20": "\u0160R" + }, + "ENE": { + "0": "\u897f\u5317\u897f", + "2": "\u6771\u5317\u504f\u6771", + "3": "ENE", + "4": "E-N-E", + "5": "ENE", + "6": "ENE", + "8": "ENE", + "9": "ENE", + "10": "ENE", + "13": "DKD", + "14": "VSV", + "16": "Ost-Nordost", + "20": "R\u0160R" + }, + "E": { + "0": "\u897f", + "2": "\u6771", + "3": "E", + "4": "E", + "5": "E", + "6": "E", + "8": "E", + "9": "L", + "10": "E", + "13": "D", + "14": "V", + "16": "\u00d6st", + "20": "R" + }, + "ESE": { + "0": "\u897f\u5357\u897f", + "2": "\u6771\u5357\u7bc7\u6771", + "3": "ESE", + "4": "E-S-E", + "5": "ESE", + "6": "ESE", + "8": "ESE", + "9": "ESE", + "10": "ESE", + "13": "DGD", + "14": "VJV", + "16": "\u00d6st-Sydost", + "20": "RPR" + }, + "SE": { + "0": "\u5357\u897f", + "2": "\u6771\u5357", + "3": "SE", + "4": "S-E", + "5": "SE", + "6": "SE", + "8": "SE", + "9": "SE", + "10": "SE", + "13": "GD", + "14": "JV", + "16": "Sydost", + "20": "PR\n" + }, + "SSE": { + "0": "\u5357\u5357\u897f", + "2": "\u6771\u5357\u504f\u5357", + "3": "SSE", + "4": "S-S-E", + "5": "SSE", + "6": "SSE", + "8": "SSE", + "9": "SSE", + "10": "SSE", + "13": "GGD", + "14": "JJV", + "16": "Syd-Sydost", + "20": "PPR" + }, + "S": { + "0": "\u5357", + "2": "\u5357", + "3": "S", + "4": "S", + "5": "S", + "6": "S", + "8": "S", + "9": "S", + "10": "S", + "13": "G", + "14": "J", + "16": "S\u00f6der", + "20": "P" + }, + "SSW": { + "0": "\u5357\u5357\u6771", + "2": "\u897f\u5357\u504f\u5357", + "3": "SSW", + "4": "S-S-O", + "5": "SSW", + "6": "SSW", + "8": "SSW", + "9": "SSO", + "10": "SSW", + "13": "GGB", + "14": "JJZ", + "16": "Syd-Sydv\u00e4st", + "20": "PPV" + }, + "SW": { + "0": "\u5357\u6771", + "2": "\u897f\u5357", + "3": "SW", + "4": "S-O", + "5": "SW", + "6": "SW", + "8": "SW", + "9": "SO", + "10": "SW", + "13": "GB", + "14": "JZ", + "16": "Sydv\u00e4st", + "20": "PV" + }, + "WSW": { + "0": "\u6771\u5357\u6771", + "2": "\u897f\u5357\u504f\u897f", + "3": "WSW", + "4": "O-S-O", + "5": "WSW", + "6": "WSW", + "8": "WSW", + "9": "OSO", + "10": "WSW", + "13": "BKB", + "14": "ZJZ", + "16": "V\u00e4st-Sydv\u00e4st", + "20": "VPV" + }, + "W": { + "0": "\u6771", + "2": "\u897f", + "3": "W", + "4": "O", + "5": "W", + "6": "W", + "8": "W", + "9": "O", + "10": "W", + "13": "B", + "14": "Z", + "16": "V\u00e4st", + "20": "V" + }, + "WNW": { + "0": "\u6771\u5317\u6771", + "2": "\u897f\u5317\u504f\u897f", + "3": "WNW", + "4": "O-N-O", + "5": "WNW", + "6": "WNW", + "8": "WNW", + "9": "ONO", + "10": "WNW", + "13": "BKB", + "14": "ZSZ", + "16": "V\u00e4st-Nordv\u00e4st", + "20": "V\u0160V" + }, + "NW": { + "0": "\u5317\u6771", + "2": "\u897f\u5317", + "3": "NW", + "4": "N-O", + "5": "NW", + "6": "NW", + "8": "NW", + "9": "NO", + "10": "NW", + "13": "KB", + "14": "SZ", + "16": "Nordv\u00e4st", + "20": "\u0160V" + }, + "NNW": { + "0": "\u5317\u5317\u6771", + "2": "\u897f\u5317\u504f\u5317", + "3": "NNW", + "4": "N-N-O", + "5": "NNW", + "6": "NNW", + "8": "NNW", + "9": "NNO", + "10": "NNW", + "13": "KKB", + "14": "SSZ", + "16": "Nord-Nordv\u00e4st", + "20": "\u0160\u0160V" + }, + "Unknown": { + "0": "\u4e0d\u660e", + "2": "\u4e0d\u660e", + "3": "Unknown", + "4": "Inconnu", + "5": "Unbekannt", + "6": "Sconosciuto", + "8": "Nieznane", + "9": "Desconhecido", + "10": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439", + "13": "Bilinmeyen", + "14": "Neznamy", + "16": "Ok\u00e4nd", + "20": "Ne\u017einoma" + }, + "NoTickets": { + "0": "Xml\u30d5\u30a1\u30a4\u30eb\u306b\u767b\u9332\u3055\u308c\u305f\u4ea4\u901a\u5207\u7b26\u304c\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002", + "3": "There were no Traffic Tickets in xml file which registered in it.", + "6": "Non c'erano biglietti del traffico nel file xml in esso registrato.", + "8": "Nie znaleziono \u017cadnych zarejestrowanych mandat\u00f3w w pliku xml", + "9": "N\u00e3o h\u00e1 nenhuma multa de tr\u00e2nsito no arquivo xml registrada.", + "10": "\u041d\u0435\u0442 \u041a\u0432\u0438\u0442\u0430\u043d\u0446\u0438\u0438", + "14": "V souboru xml nebyly najite zadne dopravni pokuty, ktere by se v nem registrovaly.", + "16": "Det fanns inga trafik b\u00f6ter i .xml filen som kunde laddas in.", + "20": "Nebuvo rasta joki\u0173 baud\u0173 xml faile" + }, + "NoDeadBodies": { + "0": "\u8fd1\u304f\u306b\u6b7b\u4f53\u306f\u3042\u308a\u307e\u305b\u3093\u3002", + "3": "There are no dead bodies nearby you.", + "5": "Keine Leiche in der N\u00e4he", + "6": "Non ci sono cadaveri vicino a te.", + "8": "W pobli\u017cu Ciebie nie znajduj\u0105 si\u0119 \u017cadne martwe cia\u0142a.", + "9": "N\u00e3o existem corpos perto de voc\u00ea.", + "10": "\u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0442\u0440\u0443\u043f\u043e\u0432", + "14": "Ve vasem okoli nejsou zadna mrtva tela.", + "16": "Det finns inga d\u00f6da kroppar n\u00e4ra dig.", + "20": "N\u0117ra negyv\u0173 k\u016bn\u0173 prie tav\u0119s" + }, + "Coroner": { + "0": "\u691c\u8996\u5b98", + "3": "Coroner", + "5": "Gerichtsmediziner", + "6": "Scientifica /ris", + "8": "Koroner", + "9": "M\u00e9dico Legista", + "10": "\u041a\u043e\u0440\u043e\u043d\u0435\u0440", + "14": "Koroner", + "16": "R\u00e4ttsl\u00e4kare", + "20": "Medicinos Ekspertas" + }, + "CoronerComment0": { + "0": "\u304a\u75b2\u308c\u69d8\u3067\u3059\u3002\u6b7b\u4f53\u306e\u51e6\u7406\u3092\u884c\u3044\u307e\u3059\u3002", + "3": "Thank you for your work. We will dispose of the corpse.", + "5": "Wir danken Ihnen f\u00fcr die Arbeit. Wir werden den Leichnam mitnehmen.", + "6": "Grazie per il tuo lavoro. Ci occuperemo del cadavere.", + "8": "Dzi\u0119kuj\u0119 za prac\u0119. Pozb\u0119dziemy si\u0119 zw\u0142ok.", + "9": "Obrigado pelo seu trabalho. Nos vamos remover o corpo.", + "14": "Dekuji za vasi praci. Za uklizeni mrtveho tela.", + "16": "Tack f\u00f6r ditt jobb. Vi tar hand om kroppen.", + "20": "D\u0117koju u\u017e tavo darb\u0105. Mes pasir\u016bpinsime k\u016bnu." + }, + "CoronerComment1": { + "0": "\u306f\u3041\u2026\u307e\u305f\u6b7b\u4f53\u3067\u3059\u304b\u3002\u4eca\u65e5\u30675\u4ef6\u76ee\u3067\u3059\u3088?", + "3": "Oh...another dead body? This is the fifth one today.", + "5": "Oh... Noch eine Leiche? Das ist heute schon die f\u00fcnfte.", + "6": "Oh...un altro cadavere? Questo \u00e8 il quinto di oggi", + "8": "Och...kolejny trup? To ju\u017c pi\u0105ty dzisiaj.", + "9": "Eita... outro cad\u00e1ver? J\u00e1 \u00e9 o quinto hoje.", + "14": "Oh...dalsi obet? Dnesks je to uz pata.", + "16": "Oh... \u00e4nnu en d\u00f6d kropp? Det h\u00e4r \u00e4r den femte idag!", + "20": "A.. Dar vienas negyvas k\u016bnas? \u0160iandien jau penktasis." + }, + "CoronerComment2": { + "0": "\u4e00\u4f53\u4f55\u304c\u3042\u3063\u305f\u3089\u3053\u3093\u306a\u3053\u3068\u306b\u306a\u308b\u3093\u3060\u308d\u3046?", + "3": "What in the world could have caused this?", + "5": "Was in der Welt h\u00e4tte das verursachen k\u00f6nnen?!", + "6": "Cosa diavolo potrebbe aver causato questo?", + "8": "Co na \u015bwiecie mog\u0142oby to spowodowa\u0107?", + "9": "Mas o que diabos fez isso?", + "14": "Co to proboha mohlo zpusobit?", + "16": "Vad i hela friden kan ha orsakat detta?", + "20": "Kaip i\u0161vis taip \u012fmanoma?" + }, + "CoronerComment3": { + "0": "\u3072\u3069\u3044\u73fe\u5834\u3060\u306a\u3002", + "3": "What a terrible site.", + "5": "Oh gott, was eine schreckliche Seite..", + "6": "Che posto terribile.", + "8": "Co za okropny widok.", + "9": "Mas que cena horr\u00edvel!", + "14": "Jak je na to hrozny pohled.", + "16": "Vilken hemsk syn.", + "20": "\u017diaurus \u012fvykis." + }, + "CoronerComment4": { + "0": "\u306a\u3093\u3066\u30d6\u30e9\u30c3\u30af\u306a\u795d\u65e5\u51fa\u52e4\u306a\u3093\u3060\u3002", + "3": "What a black holiday workday.", + "5": "Was ein schlechter Arbeitstag heute..", + "6": "Che giornata lavorativa festiva nera.", + "8": "C\u00f3\u017c za ci\u0119\u017cka praca", + "9": "Que feriado macabro.", + "14": "Jaky cerny svatecni pracovni den.", + "16": "Vilken m\u00f6rk arbetsdag.", + "20": "Kokia juoda \u0161ventin\u0117 darbo diena.." + }, + "CoronerComment5": { + "0": "\u30ab\u30e1\u30e9\u306e\u30d5\u30a3\u30eb\u30e0\u6b8b\u3063\u3066\u305f\u304b\u306a?", + "3": "I wonder if there's any film left from the camera.", + "5": "Ich frage mich, ob die Kamera das aufgenommen hat..", + "6": "chiss\u00e0 se \u00e8 rimasta della pellicola della macchina da presa.", + "8": "Ciekawe, czy zosta\u0142 jaki\u015b film z aparatu.", + "9": "Ser\u00e1 que ainda restou algum filme dentro da camera?", + "14": "Zajimalo by me, jestli z kamery zbyl nejaky film.", + "16": "Jag undrar om det finns n\u00e5gon video kvar fr\u00e5n kameran.", + "20": "\u012edomu ar fotoaparate liko vaizdo \u012fra\u0161as." + }, + "CoronerComment6": { + "0": "\u65e9\u304f\u65b0\u3057\u3044\u8077\u3092\u63a2\u3057\u305f\u3044\u3088\u3002", + "3": "I can't wait to find a new job.", + "5": "Ich brauche unbedingt einen neuen Job..", + "6": "Non vedo l'ora di trovare un nuovo lavoro.", + "8": "Nie mog\u0119 si\u0119 doczeka\u0107, a\u017c znajd\u0119 now\u0105 prac\u0119.", + "9": "Mal posso esperar para achar um novo emprego.", + "14": "Nemuzu se dockat, az si najdu novou praci.", + "16": "Jag kan inte v\u00e4nta p\u00e5 att byta jobb.", + "20": "Nekantrauju susirasti nauja darb\u0105." + }, + "CoronerBye": { + "0": "\u3067\u306f\u304a\u5de1\u308a\u3055\u3093\u3001\u826f\u3044\u4e00\u65e5\u3092!", + "3": "Have a good day, officer!", + "5": "Ich w\u00fcnsche Ihnen noch einen sch\u00f6nen Tag!", + "6": "Buona giornata, agente!", + "8": "Mi\u0142ego dnia, panie oficerze!", + "9": "Tenha um bom dia, policial!", + "10": "\u041a\u043e\u0440\u043e\u043d\u0435\u0440, \u0434\u0430 \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u0435", + "14": "Hezky den, strazniku!", + "16": "Hejd\u00e5! Ha en bra dag!", + "20": "Geros dienos, pareig\u016bne!" + }, + "Human": { + "0": "\u4eba", + "3": "Human", + "5": "Mensch\n", + "6": "Umano", + "8": "Cz\u0142owiek", + "9": "Humano", + "10": "\u0427\u0435\u043b\u043e\u0432\u0435\u043a", + "14": "Clovek ", + "16": "M\u00e4nniska", + "20": "\u017dmogaus" + }, + "Animal": { + "0": "\u52d5\u7269", + "3": "Animal", + "5": "Tier", + "6": "Animale", + "8": "Zwierz\u0119", + "9": "Animal", + "10": "\u0416\u0438\u0432\u043e\u0442\u043d\u043e\u0435", + "14": "Zvire ", + "16": "Djur", + "20": "Gyv\u016bno" + }, + "CODElectricalShock": { + "0": "\u96fb\u6c17\u30b7\u30e7\u30c3\u30af", + "3": "Electrical Shock", + "5": "Stromschlag", + "6": "Scossa elettrica", + "8": "Pora\u017cenie pr\u0105dem", + "9": "Choque el\u00e9trico.", + "10": "\u041a\u043e\u0434 \u041f\u043e\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043a\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0442\u043e\u043a\u043e\u043c", + "14": "Elektricky sok", + "16": "Elektrisk Chock\n", + "20": "Elektros \u0161okas" + }, + "CODDrownding": { + "0": "\u6eba\u6b7b", + "3": "Drownding", + "5": "Ertrinken", + "6": "Annegamento", + "8": "Utoni\u0119cie", + "9": "Afogamento", + "10": "\u041a\u043e\u0434 \u0423\u0442\u043e\u043d\u0443\u043b", + "14": "utopenim ", + "16": "Drunkning", + "20": "Paskendimas" + }, + "CODBang": { + "0": "\u5f37\u6253", + "3": "Bang", + "5": "Bang", + "6": "Scoppio", + "8": "Uderzenie", + "9": "Pancada", + "10": "\u041a\u043e\u0434 \u043f\u043e\u0434\u043e\u0440\u0432\u0430\u043b\u0441\u044f", + "14": "uder ", + "16": "Sm\u00e4ll", + "20": "Susitrenkimas" + }, + "CODRunOverByCar": { + "0": "\u8eca\u4e21\u306b\u8f62\u304b\u308c\u305f", + "3": "Run Over by Car", + "5": "Von einem Auto \u00fcberfahren", + "6": "Investito in auto", + "8": "Potr\u0105cenie przez samoch\u00f3d", + "9": "Atropelamento por carro.", + "14": "Prejeti autem", + "16": "P\u00e5k\u00f6rd av bil", + "20": "Perva\u017eiavimas automobiliu" + }, + "CODFall": { + "0": "\u9ad8\u6240\u304b\u3089\u306e\u8ee2\u843d", + "3": "Fall", + "5": "Sturz\n", + "6": "Caduta ", + "8": "Upadek", + "9": "Queda", + "10": "\u041f\u0430\u0434\u0435\u043d\u0438\u0435", + "14": "Pad", + "16": "Fall", + "20": "Nukritimas" + }, + "CODAnimal": { + "0": "\u52d5\u7269\u306b\u3088\u308b\u5916\u50b7", + "3": "Animal", + "5": "Tier", + "6": "Animale", + "8": "Zwierz\u0119", + "9": "Animal", + "10": "\u0416\u0438\u0432\u043e\u0442\u043d\u043e\u0435", + "14": "Zvire ", + "16": "Djur", + "20": "Gyv\u016bnas" + }, + "CODExplosion": { + "0": "\u7206\u767a", + "3": "Explosion", + "5": "Explosion", + "6": "Esplosione", + "8": "Wybuch", + "9": "Explos\u00e3o", + "14": "Vybuch ", + "16": "Explosion", + "20": "Sprogimas" + }, + "CODBleeding": { + "0": "\u5927\u91cf\u51fa\u8840", + "3": "Bleeding", + "5": "Blutungen", + "6": "Sanguinamento", + "8": "Wykrwawienie", + "9": "Sangramento", + "14": "Vykrvaceni ", + "16": "Kraftiga bl\u00f6dningar", + "20": "Nukraujavimas" + }, + "CODBarbedWire": { + "0": "\u6709\u523a\u9244\u7dda", + "3": "Barbed Wire", + "5": "Gekappte Kabel", + "6": "Filo spinato", + "8": "Drut kolczasty ", + "9": "Arame farpado", + "14": "Ostnaty drat", + "16": "Taggtr\u00e5d", + "20": "Spygliuota viela" + }, + "CODExhaustion": { + "0": "\u904e\u52b4\u6b7b", + "3": "Exhaustion", + "5": "Ersch\u00f6pft", + "6": "Esaurimento", + "8": "Wyczerpanie", + "9": "Exaust\u00e3o", + "14": "Vycerpani", + "16": "Utmattning", + "20": "Nuovargis" + }, + "CODBurn": { + "0": "\u706b\u50b7", + "3": "Burn", + "5": "Verbrennungen\n", + "6": "Bruciare", + "8": "Spalony", + "9": "Queimadura", + "14": "Ohnem ", + "16": "Br\u00e4nnskador", + "20": "Nudegimas" + }, + "CODHelicopterCrash": { + "0": "\u30d8\u30ea\u306e\u589c\u843d", + "3": "Heli Crash", + "5": "Helikopter Unfall", + "6": "Incidente elicottero ", + "8": "Katastrofa helikoptera", + "9": "Acidente de helic\u00f3ptero", + "10": "\u041f\u0430\u0434\u0435\u043d\u0438\u0435 \u0432\u0435\u0440\u0442\u043e\u043b\u0451\u0442\u0430", + "14": "Havarie vrtulniku", + "16": "Helikopterkrasch", + "20": "Sraigtasparnio avarija" + }, + "CODChoking": { + "0": "\u7a92\u606f", + "3": "Chocking", + "5": "Ausbremsen", + "6": "Soffocamento", + "8": "Ud\u0142awienie si\u0119", + "9": "Enforcamento", + "14": "Ucpanim ", + "16": "Kv\u00e4vning", + "20": "Paspringimas" + }, + "CODKnife": { + "0": "\u30ca\u30a4\u30d5\u3067\u523a\u3055\u308c\u305f", + "3": "Stabbed by knife", + "5": "Schwere K\u00f6rperverletzung", + "6": "Colpito da un coltello", + "8": "Zad\u017aganie no\u017cem", + "9": "Esfaqueamento", + "10": "\u041d\u043e\u0436", + "14": "Bodnuti nozem", + "16": "Knivhuggen", + "20": "Peilis" + }, + "CODBeatenBlunt": { + "0": "\u920d\u5668\u3067\u6bb4\u3089\u308c\u305f", + "3": "Beaten by blunt", + "6": "Colpito da corpo a corpo", + "8": "Pobity obuchem", + "9": "Espancamento com arma branca", + "14": "Porazen tupou veci ", + "16": "Slagen av ett f\u00f6rem\u00e5l", + "20": "Sumu\u0161imas su lazda" + }, + "CODBeatenSome": { + "0": "\u4f55\u304b\u3067\u6bb4\u3089\u308c\u305f", + "3": "Beaten by something", + "5": "K\u00f6rperverletzung", + "6": "Battuto da qualcosa", + "8": "Pobity", + "9": "Espancado por algo", + "14": "Necim umlaceny ", + "16": "Slagen av n\u00e5got", + "20": "Sumu\u0161imas su ka\u017ekuo" + }, + "CODBeatenHand": { + "0": "\u7d20\u624b\u3067\u6bb4\u3089\u308c\u305f", + "3": "Beaten by hand", + "5": "K\u00f6rperverletzung", + "6": "battuto a mano", + "8": "Pobicie", + "9": "Espancamento a m\u00e3o", + "14": "Utluceny rucne ", + "16": "Slagen med bara h\u00e4nder", + "20": "Sumu\u0161imas kum\u0161\u010diais" + }, + "CODShotPistol": { + "0": "\u62f3\u9283\u3067\u6483\u305f\u308c\u305f", + "3": "Shot by pistol", + "5": "Von einer Schusswaffe angeschossen", + "6": "Colpo di pistola", + "8": "Postrza\u0142 z pistoletu", + "9": "Baleado por pistola", + "10": "\u0421\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0437 \u043f\u0438\u0441\u0442\u043e\u043b\u0435\u0442\u0430", + "14": "strelou z pistole", + "16": "Skjuten av en pistol", + "20": "Pa\u0161ovimas rankiniu ginklu" + }, + "CODShotHeavyFirearm": { + "0": "\u9283\u5668\u3067\u6483\u305f\u308c\u305f", + "3": "Shot by heavy firearm", + "5": "Von einer schweren Schusswaffe angeschossen", + "6": "Colpito da arma da fuoco pesante", + "8": "Postrza\u0142 z ci\u0119\u017ckiej broni palnej", + "9": "Baleado por arma de fogo pesada", + "10": "\u0421\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0437 \u0442\u044f\u0436\u0435\u043b\u043e\u0433\u043e \u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d\u0438\u044f", + "14": "Zastrelen tezkou strelnou zbrani", + "16": "Skjuten av st\u00f6rre skjutvapen", + "20": "Pa\u0161ovimas sunkiu ginklu" + }, + "CODShotShotgun": { + "0": "\u6563\u5f3e\u9283\u3067\u6483\u305f\u308c\u305f", + "3": "Shot by shotgun", + "5": "Von einer Schrotflinte angeschossen", + "6": "Colpito da un fucile", + "8": "Postrza\u0142 z strzelby", + "9": "Baleado por escopeta", + "10": "\u0421\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0437 \u0434\u0440\u043e\u0431\u043e\u0432\u0438\u043a\u0430", + "14": "Zastrelen brokovnici", + "16": "Skjuten av hagelgev\u00e4r", + "20": "Pa\u0161ovimas \u0161autuvu" + }, + "CODShotRifle": { + "0": "\u30e9\u30a4\u30d5\u30eb\u3067\u6483\u305f\u308c\u305f", + "3": "Shot by Rifle", + "5": "Von einem Sturmgewehr angeschossen", + "6": "Colpito da un fucile", + "8": "Postrza\u0142 z karabinu", + "9": "Beleado por rifle", + "10": "\u0421\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0437 \u0440\u0443\u0436\u044c\u044f", + "14": "Zastrelen puskou ", + "16": "Skjuten av gev\u00e4r", + "20": "Pa\u0161ovimas kulkosvaid\u017eiu" + }, + "CODUnknown": { + "0": "\u6b7b\u56e0\u4e0d\u660e", + "3": "Unknown cause of death", + "5": "Unbekannte Todesursache", + "6": "Causa sconosciuta della morte", + "8": "Nieznany", + "9": "Causa da morte desconhecida", + "10": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e", + "14": "Neznama pricina smrti", + "16": "Ok\u00e4nd d\u00f6dsorsak", + "20": "Ne\u017einoma" + }, + "TeleportUnit": { + "0": "{0}\u3067\u8fd1\u304f\u306b\u30c6\u30ec\u30dd\u30fc\u30c8", + "3": "Press {0} to teleport nearby you.", + "5": "Dr\u00fccke {0} um in deine N\u00e4he zu teleportieren.", + "6": "Premi {0} per teletrasportarti vicino a te.", + "8": "Naci\u015bnij {0} by teleportowa\u0107 samoch\u00f3d blisko ciebie.", + "9": "Pressione {0} para teleportar para perto de voc\u00ea.", + "14": "Stisknutim tlacitka {0} se teleportujete pobliz.", + "16": "Tryck p\u00e5 {0} f\u00f6r att teleportera i n\u00e4rheten.", + "20": "Paspausk {0}, norint atgabenti ekipa\u017e\u0105 prie tav\u0119s" + }, + "UnitRequested": { + "0": "~b~{0}~s~\u3092\u672c\u90e8\u306b\u8981\u8acb\u3057\u307e\u3057\u305f\u3002", + "3": "Requested ~b~{0}~s~ unit to dispatch.", + "5": "~b~{0}~s~ wurde zum Einsatz dazu gerufen.", + "6": "~b~{0}~s~ unit\u00e0 richiesta da inviare.", + "8": "Poproszono o wys\u0142anie jednostki ~b~{0}~s~.", + "9": "Pedido ~b~{0}~s~unidade para central", + "14": "Pozadovana jednotka ~b~{0}~s~ k odeslani.", + "16": "RLC, kan vi f\u00e5 en ~b~{0}~s~ enhet till platsen?", + "20": "Dispe\u010derin\u0117, reikalauju ~b~{0}~s~ " + }, + "Name": { + "0": "\u540d\u524d", + "3": "Name", + "6": "Nome", + "14": "Nazev", + "16": "Namn", + "20": "Vardas" + }, + "CauseOfDeath": { + "0": "\u6b7b\u56e0", + "3": "Cause of Death", + "6": "Causa di morte", + "14": "Pricina smrti", + "16": "D\u00f6dsorsak", + "20": "Mirties prie\u017eastis" + }, + "DiedDay": { + "0": "\u6b7b\u4ea1\u65e5", + "3": "Died Day", + "6": "Giorno della morte", + "14": "Den smrti", + "16": "De d\u00f6das dag", + "20": "Mirties data" + }, + "Sex": { + "0": "\u6027\u5225", + "3": "Sex", + "6": "Sesso", + "14": "Pohlavi", + "16": "Sex", + "20": "Lytis" + }, + "CoronerCheckPls": { + "0": "\u8a73\u3057\u3044\u907a\u4f53\u306e\u60c5\u5831\u306f\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002", + "3": "If you want to more details of dead bodies, please check the database.", + "6": "Se vuoi maggiori dettagli sui cadaveri, controlla il database.", + "14": "Pokud chcete vice podrobnosti o mrtvych telech, podivejte se do databaze.", + "16": "Om du vill ha mer detaljer \u00f6ver de d\u00f6da, kolla databasen.", + "20": "Jeigu norite su\u017einoti daugiau duomen\u0173 apie mirtis, patikrinkite duomen\u0173 baz\u0119" + }, + "NoData": { + "0": "\u30c7\u30fc\u30bf\u306a\u3057", + "3": "No Data" + }, "Fraud": { "0": "\u8a50\u6b3a\u88ab\u5bb3\u306e\u901a\u5831", "1": "\u6b3a\u8bc8\u7f6a", @@ -235,6 +1082,7 @@ "5": "Betrug", "6": "Frode", "8": "Oszustwo", + "9": "Fraude", "10": "\u041c\u043e\u0448\u0435\u043d\u043d\u0438\u0447\u0435\u0441\u0442\u0432\u043e", "11": "Fraude", "12": "Fraude", @@ -255,6 +1103,7 @@ "5": "Gang Schie\u00dferei", "6": "Sparatoria tra bande", "8": "Strzelanina Gang\u00f3w ", + "9": "Tiroteio de Gangue", "10": "\u041f\u0435\u0440\u0435\u0441\u0442\u0440\u0435\u043b\u043a\u0430 \u0431\u0430\u043d\u0434", "11": "Tiroteo de pandillas", "12": "Tiroteo de pandillas", @@ -275,6 +1124,7 @@ "5": "Illegaler Download", "6": "Download illegale", "8": "Plik pobrany z nielegalnego \u017ar\u00f3d\u0142a ", + "9": "Download Ilegal", "10": "\u041d\u0435\u0437\u0430\u043a\u043e\u043d\u043d\u0430\u044f \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430", "11": "Descarga de archivos ilegales", "12": "Descarga ilegal", @@ -295,6 +1145,7 @@ "5": "Illegaler expliziter Inhalt", "6": "Contenuto sessuale illegale", "8": "Posiadanie nielegalnej pornografii", + "9": "Conte\u00fado Sexual Ilegal", "10": "\u041d\u0435\u0437\u0430\u043a\u043e\u043d\u043d\u044b\u0439\u0421\u0435\u043a\u0441\u0443\u0430\u043b\u044c\u043d\u044b\u0439\u041a\u043e\u043d\u0442\u0435\u043d\u0442", "11": "Posesi\u00f3n de pornograf\u00eda ilegal", "12": "Cotenido sexual ilegal", @@ -315,6 +1166,7 @@ "5": "Einsch\u00fcchterung", "6": "Intimidazione", "8": "Zastraszanie", + "9": "Intimida\u00e7\u00e3o", "10": "\u0417\u0430\u043f\u0443\u0433\u0438\u0432\u0430\u043d\u0438\u0435", "11": "Intimidaci\u00f3n", "12": "Intimidacion", @@ -335,6 +1187,7 @@ "5": "Mord", "6": "Omicidio", "8": "Morderstwo", + "9": "Assassinato", "10": "\u0423\u0431\u0438\u0439\u0441\u0442\u0432\u043e", "11": "Asesinato", "12": "Asesinato", @@ -355,6 +1208,7 @@ "5": "Vergewaltigung", "6": "Stupro", "8": "Gwa\u0142t", + "9": "Estupro", "10": "\u0418\u0437\u043d\u0430\u0441\u0438\u043b\u043e\u0432\u0430\u043d\u0438\u0435", "11": "Violaci\u00f3n", "12": "Violaci\u00f3n", @@ -375,6 +1229,7 @@ "5": "Gestohlenes Auto - Verfolgungsjagd", "6": "Inseguimento auto rubata", "8": "Po\u015bcig za skradzionym pojazdem ", + "9": "Persegui\u00e7\u00e3o a Carro Roubado", "10": "\u041f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0443\u0433\u043d\u0430\u043d\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u044b", "11": "Persecuci\u00f3n de coche robado", "12": "Persecucion de vehiculo robado", @@ -395,6 +1250,7 @@ "5": "Voyeurismus", "6": "Guardone /maniaco", "8": "Podgl\u0105dacz", + "9": "Voyeurismo", "10": "\u0412\u0443\u0430\u0439\u0435\u0440\u0438\u0437\u043c", "11": "Voyeurismo", "12": "Voyerismo", @@ -415,6 +1271,7 @@ "5": "Hacking Ermittlung", "6": "Indagine", "8": "\u015aledztwo a sprawie hackera", + "9": "Investiga\u00e7\u00e3o de Hack", "10": "\u0420\u0430\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0437\u043b\u043e\u043c\u0430", "11": "Investigaci\u00f3n de hackear", "12": "Investigaci\u00f3n de hackear", @@ -435,6 +1292,7 @@ "5": "Gesuchter Krimineller gefunden", "6": "Trovare criminale ricercato", "8": "Znaleziono poszukiwanego przest\u0119pc\u0119", + "9": "Criminoso Procurado Encontrado", "10": "\u0420\u0430\u0437\u044b\u0441\u043a\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u0435\u0441\u0442\u0443\u043f\u043d\u0438\u043a \u043d\u0430\u0439\u0434\u0435\u043d", "11": "Encontrado criminal buscado", "12": "Criminal buscado encontrado", @@ -454,6 +1312,7 @@ "5": "Dynamische Verfolgungsjagd", "6": "Ricerca Dinamica", "8": "Dynamiczny Po\u015bcig ", + "9": "Persegui\u00e7\u00e3o Din\u00e2mica", "10": "\u0414\u0438\u043d\u0430\u043c\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435", "11": "Persecuci\u00f3n din\u00e1mica", "12": "Persecucion din\u00e1mica", @@ -473,6 +1332,7 @@ "5": "Stra\u00dfenpr\u00fcgelei", "6": "Rissa in strada", "8": "B\u00f3jka uliczna", + "9": "Briga de Rua", "10": "\u0423\u043b\u0438\u0447\u043d\u0430\u044f \u0434\u0440\u0430\u043a\u0430", "11": "Pelea callejera", "12": "Pelea callejera", @@ -492,6 +1352,7 @@ "5": "Panic Button", "6": "Pulsante antipanico\n", "8": "Policjant wcisn\u0105\u0142 przycisk alarmowy ", + "9": "Bot\u00e3o do P\u00e2nico", "10": "\u0422\u0440\u0435\u0432\u043e\u0436\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", "11": "Bot\u00f3n de p\u00e1nico", "12": "Bot\u00f3n de p\u00e1nico", @@ -511,6 +1372,7 @@ "5": "Sushi Terrorismus", "6": "Terrorismo del sushi", "8": "Problem z klientem w restauracji sushi ", + "9": "Terrorismo no Sushi", "10": "T\u0435\u0440\u0440\u043e\u0440\u0438\u0437\u043c", "11": "Un esc\u00e1ndalo en un restaurante de sushi", "13": "Sorunlu M\u00fc\u015fteri", @@ -529,6 +1391,7 @@ "5": "Geklauter Geld Transport", "6": "Furgone portavalori rubato", "8": "Skradziona furgonetka z pieni\u0119dzmi ", + "9": "Carro Forte Roubado", "10": "\u0423\u0433\u043d\u0430\u043d\u0430 \u0438\u043d\u043a\u0430\u0441\u0441\u0430\u0442\u043e\u0440\u0441\u043a\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430", "11": "Robo de cami\u00f3n con dinero ", "13": "\u00c7al\u0131nt\u0131 Banka Arac\u0131", @@ -547,6 +1410,7 @@ "5": "Laden Diebstahl", "6": "Rapina in un negozio", "8": "Napad na sklep", + "9": "Roubo de Loja", "10": "\u041e\u0433\u0440\u0430\u0431\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430", "11": "Atraco a una tienda", "13": "D\u00fckkan Soygunu", @@ -557,109 +1421,201 @@ "19": "KauppaRy\u00f6st\u00f6", "20": "Parduotuv\u0117s apipl\u0117\u0161imas" }, + "BankRobbery": { + "0": "\u9280\u884c\u5f37\u76d7", + "2": "\u9280\u884c\u6436\u52ab", + "3": "Bank Robbery", + "4": "Braquage d'une banque", + "5": "Bank\u00fcberfall", + "6": "Rapina in banca", + "8": "Napad na bank", + "9": "Roubo ao Banco", + "10": "\u041e\u0433\u0440\u0430\u0431\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u043d\u043a\u0430", + "13": "Banka Soygunu", + "14": "Bankovni loupez", + "16": "Bankr\u00e5n", + "20": "Banko apipl\u0117\u0161imas" + }, + "HitAndRun": { + "0": "\u3072\u304d\u9003\u3052", + "2": "\u8087\u4e8b\u9003\u9038", + "3": "Hit and Run", + "4": "D\u00e9lit de fuite", + "5": "Fahrerflucht", + "6": "Pirata della strada ", + "8": "Potr\u0105cenie i ucieczka", + "9": "Batida seguido de Fuga", + "10": "\u0411\u0435\u0433\u0441\u0442\u0432\u043e \u0441 \u043c\u0435\u0441\u0442\u0430 \u0414\u0422\u041f", + "13": "Vur Ka\u00e7", + "14": "Uderit a utect", + "16": "Smitnings Olycka", + "20": "Pab\u0117gimas i\u0161 \u012fvykio vietos" + }, "StolenCarPursuitDesc": { - "0": "\u76d7\u96e3\u8eca\u4e21: ~r~{0}~s~\n\u30ca\u30f3\u30d0\u30fc: ~b~{1}~s~\n\u81f3\u6025\u76d7\u96e3\u8eca\u4e21\u306e\u8ffd\u8de1\u3092\u958b\u59cb\u305b\u3088\u3002", + "0": "\u76d7\u96e3\u8eca\u4e21: ~r~{0}~s~\n\u30ca\u30f3\u30d0\u30fc: ~b~{1}~s~\n\u76d7\u96e3\u8eca\u4e21\u306e\u8ffd\u8de1\u3092\u958b\u59cb\u305b\u3088\u3002", "2": "\u5931\u7aca\u8eca\u8f1b: ~r~{0}~s~\n\u8eca\u724c\u865f\u78bc: ~b~{1}~s~\n\u958b\u59cb\u5b9a\u4f4d\u5931\u7aca\u8eca\u8f1b\u3002", "3": "Stolen Vehicle: ~r~{0}~s~\nNumber: ~b~{1}~s~\nStart tracking the stolen vehicle now.", + "4": "Poursuite d'un v\u00e9hicule vol\u00e9", + "5": "Geklautes Fahrzeug: ~r~{0}~s~\nKennzeichen: ~b~{1}~s~\nVerfolge das gestohlene Fahrzeug.", "6": "Veicolo rubato: ~r~{0}~s~\n Numero: ~b~{1}~s~\n Inizia subito a rintracciare il veicolo rubato.", "8": "Skradziony Pojazd: ~r~{0}~s~\nNumer Rejestracyjny: ~b~{1}~s~\nNatychmiast rozpocznij \u015bledzenie skradzionego pojazdu.", + "9": "Carro Roubado: ~r~{0}~s~\nN\u00famero: ~b~{1}~s~\nComece a rastrear o ve\u00edculo roubado agora.", "10": "Stolen Vehicle: ~r~{0}~s~\nNumber: ~b~{1}~s~\nStart tracking the stolen vehicle now.", "11": "Coche robado: ~r~{0}~s~\nPlaca: ~b~{1}~s~\nComience a rastrear coche robado ahora.", "13": "\u00c7al\u0131nt\u0131 Ara\u00e7: ~r~{0}~s~\nPlaka: ~b~{1}~s~\n\u00c7al\u0131nt\u0131 arac\u0131 takip etmeye ba\u015flay\u0131n.", "14": "Ukradene vozidlo: ~r~{0}~s~\nCislo: ~b~{1}~s~\nZacnete nyni sledovat ukradene vozidlo.", "15": "Stj\u00e5let k\u00f8ret\u00f8j: ~r~{0}~s~\nNummerplade: ~b~{1}~s~\nBegynd at spore det stj\u00e5lne k\u00f8ret\u00f8j nu.", - "16": "Stulet Fordon: ~r~{0}~s~\nReg. Nummer: ~b~{1}~s~\nB\u00f6rja s\u00f6ka det stulna fordonet" + "16": "Stulet Fordon: ~r~{0}~s~\nReg. Nummer: ~b~{1}~s~\nB\u00f6rja s\u00f6ka det stulna fordonet", + "20": "Pavogtas automobilis: ~r~{0}~s~\nValstybinis numeris: ~b~{1}~s~\nPrad\u0117kite sekti pavogt\u0105 automobil\u012f" }, "GangShootoutDesc": { "0": "~r~\u8907\u6570\u306e\u30ae\u30e3\u30f3\u30b0~s~\u304c\u66b4\u8d70\u4e2d\uff01\n~r~\u7dca\u6025\u8d70\u884c~s~\u3067\u5411\u304b\u3063\u3066\u304f\u3060\u3055\u3044\u3002", "2": "~r~ \u4e00\u7fa4\u5e6b\u6d3e\u5206\u5b50 ~s~ \u6b63\u5728\u958b\u69cd\uff01\n\u8acb ~r~ \u7acb\u523b\u524d\u5f80\uff08Code 3\uff09 ~s~ \u3002", "3": "~r~Several gangs ~s~ are running wild!\nRespond with ~r~Code 3~s~.", + "4": "Fusillade entre gangs de rue", + "5": "~r~Mehrere Banden ~s~ treiben ihr Unwesen!\nAnfahrt mit ~r~Code 3~s~.", "6": "Diverse bande si stanno scatenando!\n Rispondi con Codice 3.", "8": "~r~Kilka gang\u00f3w ~s~ szaleje!\nReaguj ~r~Kodem 3~s~.", + "9": "~r~V\u00e1rias Gangues ~s~ est\u00e3o ficando enlouquecidas!\nResponda com ~r~C\u00f3digo 3~s~.", "10": "~r~Several gangs ~s~ are running wild!\nRespond with ~r~Code 3~s~.", "11": "~r~\u00a1Varias pandillas ~s~ son agresivos!\nResponde con ~r~Code 3~s~.", "13": "~r~Birka\u00e7 tane \u00e7ete ~s~ silahl\u0131 kavgaya ba\u015flam\u0131\u015f!\n~r~Acil kod~s~ ile intikal et.", "14": "~r~Nekolik gangu ~s~ radi!\nReaguj ~r~pod kodem 3~s~.", "15": "~r~Flere bander ~s~ l\u00f8ber l\u00f8bsk!\nSvar med~r~Kode 3~s~.", - "16": "~r~Flera g\u00e4ng ~s~ g\u00e5r loss\nK\u00f6r dit med ~r~Prio 1~s~." + "16": "~r~Flera g\u00e4ng ~s~ g\u00e5r loss\nK\u00f6r dit med ~r~Prio 1~s~.", + "20": "~r~Keletas gauj\u0173~s~ kovoja!\nVykite \u012f \u012fvykio viet\u0105 ~r~3 Kodu~s~" }, "WantedCriminalFoundDesc": { "0": "~r~\u6307\u540d\u624b\u914d\u72af~s~\u306b\u9177\u4f3c\u3057\u305f\u4eba\u7269\u306e\u76ee\u6483\u60c5\u5831\u3042\u308a\u3002\n~y~\u8b66\u6212\u8d70\u884c~s~\u3067\u6025\u884c\u305b\u3088\u3002", "2": "\u5831\u6848\u6c11\u8846\u89aa\u773c\u76ee\u64ca\u67d0\u4eba\u9577\u76f8\u8207 ~r~ \u901a\u7ddd\u72af ~s~ \u76f8\u4f3c\u3002\n\u8acb ~y~ \u524d\u5f80\u67e5\u770b (Code 2) ~s~\u3002", "3": "There are eyewitness reports of someone who closely resembles ~r~wanted criminal ~s~.\nRespond with ~y~Code2~s~.", + "4": "Criminel recherch\u00e9 trouv\u00e9", + "5": "Es gibt Augenzeugen die aussagen eine ~r~gesuchte Person ~s~gesehen zu haben!\nAnfahrt mit ~y~Code2~s~.", "6": "Ci sono resoconti di testimoni oculari di qualcuno che somiglia molto al ricercato criminale \n Rispondi con Codice2.", "8": "Zauwa\u017cono osob\u0119, kt\u00f3ra bardzo przypomina ~r~poszukiwanego przest\u0119pc\u0119~s~.\nReaguj ~y~Kodem 2~s~.", + "9": "Testemunhas relataram algu\u00e9m que se assemelha muito com um ~r~criminoso procurado ~s~.\nResponda com ~y~C\u00f3digo 2~s~.", "10": "There are eyewitness reports of someone who closely resembles ~r~wanted criminal ~s~.\nRespond with ~y~Code2~s~.", "11": "Testigos han visto a la persona similar a ~r~criminal buscado ~s~.\nResponde con ~y~Code2~s~.", "13": "~y~Aranan \u015fah\u0131sa benzer birisini g\u00f6rm\u00fc\u015fler,~s~ ~o~git ve kontrol et.~s~", "14": "Existuji zpravy urcitych svedku o nekom, kdo se velmi podoba hledanym zlocincum.\nReaguj pod ~y~kodem 2~s~.", "15": "Der er \u00f8jenvidnerapporter om nogen, der ligner ~r~efterlyst kriminelle ~s~.\nSvar med ~y~Kode 2~s~.", - "16": "Folk s\u00e4ger att de f\u00e5tt syn p\u00e5 en ~r~efterlyst person ~s~.\nK\u00f6r dit med ~y~Prio 2~s~." + "16": "Folk s\u00e4ger att de f\u00e5tt syn p\u00e5 en ~r~efterlyst person ~s~.\nK\u00f6r dit med ~y~Prio 2~s~.", + "20": "Liuditojai prane\u0161\u0117, kad jie reg\u0117jo ~r~ie\u0161kom\u0105 asmen\u012f ~s~\nVykite \u012f \u012fvykio viet\u0105 ~y~2 Kodu~s~" }, "DynamicPursuitDesc": { "0": "\u8b66\u5bdf\u5b98\u306e\u9759\u6b62\u3092\u632f\u308a\u5207\u308a~r~\u9003\u8d70\u4e2d~s~\u3002\n\u81f3\u6025\u5fdc\u63f4\u306b\u5411\u304b\u3048\u3002", "2": "\u8b66\u54e1\u76ee\u524d\u6b63\u8ffd\u6355\u4e00\u540d ~r~ \u9003\u9038\u4e2d~s~ \u7684\u5acc\u72af\u3002\n\u8acb ~r~ \u7acb\u523b\u652f\u63f4 \uff08Code 3\uff09 ~s~ \u3002", "3": "Shake off the police officer's stillness ~r~running ~s~.\nStart their suport ASAP.", + "4": "Poursuite dynamique", + "5": "Es wird Verst\u00e4rkung bei einer Verfolgung ben\u00f6tigt!\n Beginnen Sie so schnell wie m\u00f6glich mit Ihrer Unterst\u00fctzung!", "6": "Richiesto supporto per inseguimento \n Inizia il loro supporto al pi\u00f9 presto.", "8": "Podejrzany ~r~ucieka~s~ po tym, jak zosta\u0142 zatrzymany przez policj\u0119.\nWezwij wsparcie natychmiastowo.", + "9": "Suspeito est\u00e1 ~r~fugindo ~s~. V\u00e1 atr\u00e1s!\nPe\u00e7a refor\u00e7os IMEDIATAMENTE.", "10": "Shake off the police officer's stillness ~r~running ~s~.\nStart their suport ASAP.", "11": "Sospechoso ~r~esta escapado~s~ despues la policia se ha capturado.\nPedir refuerzos.", "13": "~y~Telsize cevap vermeyen~s~ ~b~polis memurunun~s~ ~o~yan\u0131na intikal et ve durumu kontrol et.~s~", "14": "Podezrely ~r~utika~s~ pote, co byl zadrzen policii.\nOkamzite zavolejte 10-32.", "15": "Ryst politibetjentens stilhed ~r~l\u00f8b ~s~.\nStart deres support ASAP.", - "16": "Misst\u00e4nkt p\u00e5 ~r~fri fot~s~ efter att ha gripits av polisen.\nF\u00f6rst\u00e4rkning beg\u00e4rs!" + "16": "Misst\u00e4nkt p\u00e5 ~r~fri fot~s~ efter att ha gripits av polisen.\nF\u00f6rst\u00e4rkning beg\u00e4rs!", + "20": "Pad\u0117k kolegom sustabdyti ~r~gaudynes~s~\nPrad\u0117kite vykti \u012f \u012fvykio viet\u0105!" }, "StoreRobberyDesc": { - "0": "\u30b3\u30f3\u30d3\u30cb\u3067~r~\u5f37\u76d7\u4e8b\u6848~s~\u767a\u751f\u3002\n\u65e2\u306b\u767a\u751f\u3057\u3066\u304b\u3089\u6642\u9593\u304c\u7d4c\u904e\u3057\u3066\u3044\u308b\u6a21\u69d8\u3002\n~r~\u7dca\u6025\u8d70\u884c~s~\u3067\u5411\u304b\u3048\u3002", + "0": "\u30b3\u30f3\u30d3\u30cb\u3067~r~\u5f37\u76d7\u4e8b\u6848~s~\u767a\u751f\u3002\n\u767a\u751f\u3057\u3066\u304b\u3089\u6642\u9593\u304c\u7d4c\u904e\u3002\n~r~\u7dca\u6025\u8d70\u884c~s~\u3067\u5411\u304b\u3048\u3002", "2": "\u8f44\u5340\u8d85\u5546 ~r~ \u906d\u6436 ~s~ \u3002\n\u8ddd\u96e2\u6848\u767c\u6642\u9593\u5df2\u7d93\u6709\u4e00\u6bb5\u6642\u9593\n\u8acb ~r~ \u7acb\u523b\u524d\u5f80\uff08Code 3\uff09 ~s~ \u3002", "3": "A ~r~ robbery ~s~ occurred at a store.\nIt seems that time has already passed since it occurred.\nRespond with ~r~Code3~s~.", + "4": "Braquage d'un magasin", + "5": "Ein ~r~ Raub\u00fcberfall ~s~ hat statt gefallen.\nEs sieht so aus als w\u00e4re es schon l\u00e4nger her.\nAnfahrt mit ~r~Code3~s~.", "6": "Si \u00e8 verificata una rapina in un negozio.\n Sembra che sia gi\u00e0 passato del tempo da quando \u00e8 successo.\n Rispondi con Codice3.", "8": "W sklepie spo\u017cywczym dosz\u0142o do ~r~rabunku~s~.\nWygl\u0105da na to, \u017ce min\u0119\u0142o ju\u017c troch\u0119 czasu od zdarzenia.\nReaguj ~r~Kodem 3~s~.", + "9": "Um ~r~ roubo ~s~ a uma loja aconteceu.\nParece que j\u00e1 faz um tempo do ocorrido.\nResponda com ~r~C\u00f3digo 3~s~.", "10": "A ~r~ robbery ~s~ occurred at a store.\nIt seems that time has already passed since it occurred.\nRespond with ~r~Code3~s~.", "11": "La tienda ha sido ~r~ robado ~s~.\nHa pasado alg\u00fan tiempo desde el robo.\nResponde con ~r~Code 3~s~.", "13": "~y~Bir d\u00fckkanda soygun ger\u00e7ekle\u015fmi\u015f.~s~ ~o~Git ve gerekli i\u015flemleri yap.~s~", "14": "V obchode s potravinami doslo k loupezi.\nZda se, ze od udalosti uplynul nejaky cas.\nReagovat pod ~r~kodem 3~s~.", "15": "Et ~r~ r\u00f8veri ~s~ er sket i en butik.\nDet ser ud til, at tiden allerede er g\u00e5et, siden det skete.\nSvar med ~r~Kode 3~s~.", - "16": "Ett ~r~ r\u00e5n~s~har intr\u00e4ffat i en butik.\nDet verkar som att g\u00e4rningsm\u00e4nnen redan l\u00e4mnat platsen.\nK\u00f6r dit med ~r~Prio 1~s~." + "16": "Ett ~r~ r\u00e5n~s~har intr\u00e4ffat i en butik.\nDet verkar som att g\u00e4rningsm\u00e4nnen redan l\u00e4mnat platsen.\nK\u00f6r dit med ~r~Prio 1~s~.", + "20": "~r~Apipl\u0117\u0161imas~s~ \u012fvyko parduotuv\u0117je\nPana\u0161u, lyg pra\u0117jo nema\u017eai laiko\nVykite \u012f \u012fvykio viet\u0105 ~r~3 Kodu~s~" }, "SushiTerrorismDesc": { "0": "~b~\u5bff\u53f8\u5c4b~s~\u3067\u30c8\u30e9\u30d6\u30eb\u767a\u751f\u3002\n~y~\u4ef2\u4ecb~s~\u306b\u5165\u308b\u305f\u3081\u3001~y~\u8b66\u6212\u8d70\u884c~s~\u3067\u5411\u304b\u3063\u3066\u304f\u3060\u3055\u3044\u3002", "2": "\u5831\u6848\u4eba\u70ba ~b~\u58fd\u53f8\u5e97 ~s~ \u5e97\u9577\u3002\n\u8acb ~y~\u524d\u5f80\u67e5\u770b\uff08Code2\uff09~s~ \u3002", - "3": "Trouble occurred at ~b~sushi restaurant ~s~.\nRespond with ~y~Code2~s~.", + "3": "Trouble occurred at ~b~sushi restaurant~s~.\nRespond with ~y~Code2~s~.", + "4": "Terrorisme de sushi", + "5": "Bei einem ~b~Chinesischem Restaurant ~s~ist \u00c4rger aufgetreten.\nAnfahrt mit ~y~Code2~s~.", "6": "Si \u00e8 verificato un problema al ristorante di sushi .\n Rispondi con Codice2.", "8": "K\u0142opoty w ~b~restauracji sushi~s~.\nReaguj ~y~Kodem 2~s~.", + "9": "Um problema em um ~b~restaurante de sushi ~s~.\nResponda com ~y~C\u00f3digo 2~s~.", "10": "Trouble occurred at ~b~sushi restaurant ~s~.\nRespond with ~y~Code2~s~.", "11": "Problema en el ~b~sushi restaurante~s~.\nResponde con ~y~Code 2~s~.", "13": "~y~D\u00fckkan sahibi, bir m\u00fc\u015fteriden \u015fikayet\u00e7i olmu\u015f.~s~\n~o~Olay yerine intikal et ve gerekli i\u015flemleri yap.~s~", "14": "Potize v restauraci ~b~sushi~s~.\nReagovat pod ~y~kodem 2~s~.", "15": "Der er opst\u00e5et problemer p\u00e5 en ~b~sushi restaurant ~s~.\nSvar med ~y~Kode 2~s~.", - "16": "Problem p\u00e5 ~b~sushi restaurant~s~.\nK\u00f6r dit med ~y~Prio 2~s~." + "16": "Problem p\u00e5 ~b~sushi restaurant~s~.\nK\u00f6r dit med ~y~Prio 2~s~.", + "20": "Nesusipratimas \u012fvyko ~b~su\u0161io restorane~s~\nVykite \u012f \u012fvykio viet\u0105 ~y~2 Kodu~s~" }, "StolenMoneyTruckDesc": { - "0": "~b~\u73fe\u91d1\u8f38\u9001\u8eca~s~\u304c~r~\u5f37\u596a~s~\u3055\u308c\u305f\u3068\u306e\u60c5\u5831\u3002\n\u81f3\u6025\u6025\u884c\u305b\u3088\u3002", + "0": "~b~\u73fe\u91d1\u8f38\u9001\u8eca~s~\u304c~r~\u5f37\u596a~s~\u3055\u308c\u305f\u3002\n\u81f3\u6025\u6025\u884c\u305b\u3088\u3002", "2": "\u8cc7\u8a0a\u986f\u793a\u4e00\u8f1b ~b~ \u904b\u9214\u8eca ~s~ \u906d\u5230 ~r~ \u6436\u52ab ~s~\u3002", - "3": "Information that a ~b~money truck ~s~ was ~r~jacked~s~.", + "3": "~b~Money truck ~s~ was ~r~jacked~s~.\nRespond with ~r~Code3~s~.", + "4": "V\u00e9hicule blind\u00e9 vol\u00e9", + "5": "Informanten sagen, dass ein ~b~Geldtransporter ~s~~r~gestohlen~s~ wurde.", "6": "Informazioni che un portavalori \u00e8 stato sequestrato.", "8": "Dostali\u015bmy informacj\u0119, \u017ce ~b~ pojazd do przewozu got\u00f3wki ~s~ zosta\u0142 ~r~ ukradziony ~s~.", + "9": "Informa\u00e7\u00e3o que um ~b~carro forte ~s~ foi ~r~roubado~s~.", "10": "Information that a ~b~money truck ~s~ was ~r~jacked~s~.", "11": " ~b~El cami\u00f3n con dinero~s~ ha sido~r~robado~s~.", "13": "~s~Bankaya para ta\u015f\u0131yan z\u0131rhl\u0131 arac\u0131n~g~ ~r~\u00e7al\u0131nd\u0131\u011f\u0131 y\u00f6n\u00fcnde~s~ ~y~ihbar var.~s~\n~o~Olay yerine intikal et ve gerekli i\u015flemleri yap.~s~", "14": "Obdrzeli jsme zpravu, ze bylo ~r~ odcizeno ~s~ vozidlo ~s~ s hotovosti.", "15": "Information om en ~b~penge lastbil ~s~ blev ~r~ber\u00f8vet~s~.", - "16": "Uppgifter om att en ~b~v\u00e4rde transport ~s~ har blivit~r~stulen~s~." + "16": "Uppgifter om att en ~b~v\u00e4rde transport ~s~ har blivit~r~stulen~s~.", + "20": "Informacija, kad ~b~inkasacijos automobilis~s~ buvo ~r~pavogtas~s~" }, "StreetFightDesc": { "0": "~r~\u8def\u4e0a\u3067\u6bb4\u308a\u5408\u3063\u3066\u3044\u308b~s~\u4eba\u304c\u3044\u308b\u3068\u306e\u76ee\u6483\u60c5\u5831\u3042\u308a\u3002\n~r~\u7dca\u6025\u8d70\u884c~s~\u3067\u5411\u304b\u3048\u3002", "2": "\u8f44\u5185\u767c\u751f ~r~ \u805a\u8846\u9b25\u6bc6 ~s~\n\u8acb ~r~ \u7acb\u523b\u524d\u5f80\uff08Code 3\uff09 ~s~ \u3002", "3": "~r~There are sightings~s~ of people fighting each other in the street.\nRespond with ~r~Code3~s~.", + "4": "Bagarre dans une rue", + "5": "~r~Es gibt Sichtungen~s~ von zwei Personen, die sich auf der Stra\u00dfe schlagen.\nAnfahrt mit ~r~Code 3~s~.", "6": "Segnalazione di persone che litigano per strada.\n Rispondi con Codice 3.", "8": "~r~\u015awiadkowie~s~ zg\u0142osili b\u00f3jk\u0119 na ulicy.\nReaguj ~r~Kodem 3~s~.", + "9": "~r~H\u00e1 relatos~s~ de pessoas brigando na rua.\nResponda com ~r~C\u00f3digo 3~s~.", "10": "~r~There are sightings~s~ of people fighting each other in the street.\nRespond with ~r~Code3~s~.", "11": "~r~Testigos~s~ han reportado la pelea callejera. \nRospende con ~r~Code 3~s~.", "13": "~y~Sokak ortas\u0131nda birbiriyle kavga eden \u015fah\u0131slar~s~ ~o~tespit edilmi\u015f.~s~\n~o~Olay yerine intikal et ve gerekli i\u015flemleri yap.~s~", "14": "~r~Svedci~s~ nahlasili rvacku na ulici.\nReagovat pod ~r~kodem 3~s~.", "15": "~r~Der er observationer~s~ af mennesker, der k\u00e6mper mod hinanden p\u00e5 gaden.\nSvar med ~r~Kode 3~s~.", - "16": "Folk har vittnat om ett ~r~slagsm\u00e5l~s~ mellan ett antal personer.\nK\u00f6r dit med ~r~Prio 1~s~." + "16": "Folk har vittnat om ett ~r~slagsm\u00e5l~s~ mellan ett antal personer.\nK\u00f6r dit med ~r~Prio 1~s~.", + "20": "~r~Pasteb\u0117ti~s~ \u017emon\u0117s kovojantys gatv\u0117je\nVykite \u012f \u012fvykio viet\u0105 ~r~3 Kodu~s~" + }, + "BankRobberyDesc": { + "0": "~r~\u9280\u884c\u5f37\u76d7~s~\u767a\u751f!\n\u81f3\u6025\u6025\u884c\u305b\u3088\u3002", + "2": "\u63a5\u5831\u767c\u751f~r~\u9280\u884c\u6436\u52ab~s~\n\u8acb~r~ \u7acb\u5373\u524d\u5f80\uff08Code3\uff09~s~\u3002", + "3": "~r~Bank Robbery~s~ was occurred!\nRespond with ~r~Code3~s~.", + "4": "Braquage dans une banque", + "5": "~r~Bank \u00dcberfall~s~ im Gange!\nAnfahrt in ~r~Code 3~s~.", + "6": "~r~Si \u00e8 verificata una ~r~rapina in banca~s~!\n Rispondi con ~r~Codice 3~s~.", + "8": "~r~Okradziono bank~s~!\nReaguj ~r~Kodem 3~s~.", + "9": "~r~Roubo ao banco~s~ aconteceu!\nResponda com ~r~C\u00f3digo 3~s~.", + "10": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0433\u0440\u0430\u0431\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u043d\u043a\u0430", + "13": "Belirtilen konumda ~r~Banka soygunu~s~ ger\u00e7ekle\u015ftiriliyor!\n~r~Acil kod~s~ ile intikal edin.", + "14": "Doslo k ~r~bankovni loupezi~s~! Reagujte pod ~r~Kodem 3~s~.", + "16": "Ett ~r~Bankr\u00e5n~s~ har intr\u00e4ffat.\nK\u00f6r dit med ~r~Prio 1~s~.", + "20": "\u012evyko ~r~Banko Apipl\u0117\u0161imas~s~!\nVykite \u012f \u012fvykio viet\u0105 ~r~3 Kodu~s~" + }, + "HitAndRunDesc": { + "0": "~r~\u3072\u304d\u9003\u3052~s~\u304c\u767a\u751f\u3057\u305f\u3002\n\u76ee\u6483\u8005\u304b\u3089\u8a71\u3092\u805e\u3051\u3002", + "2": "\u63a5\u5831\u767c\u751f~r~\u8087\u4e8b\u9003\u9038~s~\n\u8acb\u8207\u88ab\u5bb3\u8005\u4ea4\u8ac7\u3002", + "3": "~r~Hit and Run~s~ was occurred.\nHear from witnesses.", + "4": "D\u00e9lit de fuite", + "5": "~r~Fahrerflucht~s~ wurde begangen.\nGemeldet von Augenzeugen.", + "6": "investimento \u00e8 verificato.\n Ascolta i testimoni.", + "8": "Dosz\u0142o do ~r~Potr\u0105cenia i Ucieczki~s~.\nWys\u0142uchaj \u015bwiadk\u00f3w.", + "9": "~r~Batida seguida de fuga~s~ aconteceu.\nOu\u00e7as \u00e0s testemunhas.", + "10": "\u0421\u0431\u0438\u043b \u0438 \u0441\u0431\u0435\u0436\u0430\u043b ", + "13": "Vatanda\u015f\u0131n ~r~arac\u0131na vurup ka\u00e7m\u0131\u015flar~s~.\nG\u00f6rg\u00fc tan\u0131klar\u0131 ile g\u00f6r\u00fc\u015f ve gerekli i\u015flemleri yap.", + "14": "Doslo k ~r~Uderit a utect~s~. Vyslechni si svedky.", + "16": "En ~r~Smitnings olycka~s~ har intr\u00e4ffat.\nTa kontakt med eventuella vittnen.", + "20": "~r~Pab\u0117gimas i\u0161 autovarijos~s~ \u012fvyko\nI\u0161klausyk liudytoj\u0173" }, "Owner": { "0": "\u5e97\u4e3b", @@ -669,6 +1625,7 @@ "5": "Besitzer", "6": "Proprietario", "8": "W\u0142a\u015bciciel", + "9": "Dono", "10": "\u0412\u043b\u0430\u0434\u0435\u043b\u0435\u0446", "11": "Propietario", "13": "Sahip", @@ -687,6 +1644,7 @@ "5": "Officer", "6": "Funzionario", "8": "Funkcjonariusz", + "9": "Policial", "10": "\u041e\u0444\u0438\u0446\u0435\u0440", "11": "Polic\u00eda", "13": "Polis Memuru", @@ -705,6 +1663,7 @@ "5": "Verd\u00e4chtigter", "6": "Sospetto", "8": "Podejrzany", + "9": "Suspeito", "10": "\u041f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u044c", "11": "Sospechoso", "13": "\u015e\u00fcpheli", @@ -715,6 +1674,34 @@ "19": "Ep\u00e4ilty", "20": "\u012etariamasis" }, + "Caller": { + "0": "\u901a\u5831\u8005", + "2": "\u5831\u6848\u8005", + "3": "Caller", + "5": "Anrufer", + "6": "Chiamata", + "8": "Dzwoni\u0105cy", + "9": "Quem ligou", + "10": "\u0412\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0430\u0431\u043e\u043d\u0435\u043d\u0442", + "13": "Vatanda\u015f", + "14": "Volajici", + "16": "Uppringare", + "20": "I\u0161kviet\u0117jas" + }, + "Victim": { + "0": "\u88ab\u5bb3\u8005", + "2": "\u53d7\u5bb3\u8005", + "3": "Victim", + "5": "Opfer", + "6": "Vittima", + "8": "Ofiara", + "9": "V\u00edtima", + "10": "\u0416\u0435\u0440\u0442\u0432\u0430", + "13": "Ma\u011fdur", + "14": "Obet", + "16": "M\u00e5ls\u00e4gande", + "20": "Nukent\u0117j\u0119s" + }, "SushiTerrorismHere": { "0": "\u304a\u5de1\u308a\u3055\u3093! \u3053\u3053\u3067\u3059!", "2": "\u8b66\u5bdf\uff0c\u6211\u5728\u9019\u908a\uff01", @@ -722,6 +1709,7 @@ "5": "Officer! Ich bin hier!", "6": "Agente, \u00e8 qui!", "8": "Oficerze! Jestem tutaj!", + "9": "Policial! Estou aqui!", "10": "\u041e\u0444\u0438\u0446\u0435\u0440! \u042f \u0437\u0434\u0435\u0441\u044c!", "11": "\u00a1Se\u00f1or! \u00a1Estoy aqu\u00ed!", "13": "Memurum! Buraday\u0131m.", @@ -738,6 +1726,7 @@ "5": "Nenne deinen Namen und antworte h\u00f6flich.", "6": "Dai il tuo nome e rispondi gentilmente", "8": "Podaj swoje imi\u0119 i odpowiedz uprzejmie.", + "9": "Fale o seu nome e responda educadamente.", "10": "\u041d\u0430\u0437\u043e\u0432\u0438\u0442\u0435 \u0441\u0432\u043e\u0435 \u0438\u043c\u044f \u0438 \u043b\u044e\u0431\u0435\u0437\u043d\u043e \u043e\u0442\u0432\u0435\u0442\u044c\u0442\u0435.", "11": "Dime tu nombre y responda, por favor.", "13": "\u0130sminiz nedir, nazik\u00e7e cevap verir misiniz?", @@ -754,6 +1743,7 @@ "5": "Das ist gerade egal.", "6": "Non importa ora.", "8": "To nie ma ju\u017c znaczenia.", + "9": "N\u00e3o importa agora.", "10": "\u041d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043a\u0430\u043a.", "11": "Ya no importa.", "13": "Konumuz bu de\u011fil.", @@ -767,8 +1757,10 @@ "0": "\u540c\u60c5\u3057\u3066\u8aac\u5f97", "2": "\u52f8\u963b", "3": "Pity and persuade.", + "5": "Bemitleiden und \u00fcberzeugen.", "6": "Abbi piet\u00e0, la prego.", "8": "Lituj si\u0119 i przekonuj.", + "9": "Compade\u00e7a e Conven\u00e7a.", "10": "\u041f\u043e\u0436\u0430\u043b\u0435\u0439 \u0438 \u0443\u0431\u0435\u0434\u0438.", "11": "Compadecer y persuadir.", "13": "\u0130kna et.", @@ -785,6 +1777,7 @@ "5": "Stark kritisiert.", "6": "\u00c8 colpa tua.", "8": "Silnie krytykowany.", + "9": "Criticar veementemente.", "10": "Strongly criticized.", "11": "Fuertemente criticado.", "13": "\u015eiddetle ele\u015ftir.", @@ -801,6 +1794,7 @@ "5": "Ich ersetze den Besitzer.", "6": "Al posto del proprietario", "8": "Jestem zamiast w\u0142a\u015bciciela.", + "9": "Eu estou substituindo o dono.", "10": "\u042f \u0437\u0430\u043c\u0435\u043d\u044f\u044e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430", "11": "Estoy aqu\u00ed en lugar del propietario", "13": "\u015eiddetle ele\u015ftiriyorum.", @@ -817,6 +1811,7 @@ "5": "Es ist deine Schuld.", "6": "\u00c8 colpa tua.", "8": "To twoja wina.", + "9": "A culpa \u00e9 sua.", "10": "\u042d\u0442\u043e \u0442\u0432\u043e\u044f \u0432\u0438\u043d\u0430.", "11": "Es tu culpa", "13": "Bu senin hatan.", @@ -833,6 +1828,7 @@ "5": "Hi, kannst du mir sagen was hier passiert ist?", "6": "Ciao, potresti dirmi cosa \u00e8 successo qui?", "8": "Cze\u015b\u0107, czy m\u00f3g\u0142by\u015b mi powiedzie\u0107, co si\u0119 tutaj sta\u0142o?", + "9": "Oi, voc\u00ea pode me contar o que aconteceu aqui?", "10": "\u041f\u0440\u0438\u0432\u0435\u0442, \u043d\u0435 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0432\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u043d\u0435, \u0447\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e?", "11": "\u00bfHola, puedes dime que ha pasado aqu\u00ed?", "13": "Merhabalar, burada neler oldu b\u00f6yle?", @@ -849,6 +1845,7 @@ "5": "Ja. Ich leite ein F\u00f6rderband Sushi Restaurant,", "6": "S\u00ec. Gestisco un ristorante di sushi con nastro trasportatore,", "8": "Tak. Prowadz\u0119 restauracj\u0119 sushi.", + "9": "Sim, eu sou dono de um restaurante de sushi,", "10": "\u0414\u0430. \u042f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e \u0441\u0443\u0448\u0438-\u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u043e\u043c \u0441 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u043e\u0439,", "11": "S\u00ed, dirijo un restaurante de sushi", "13": "Ho\u015fgeldiniz memur bey, \u00f6ncelikle geldi\u011finiz i\u00e7in Allah raz\u0131 olsun. Ben burada su\u015fi restoran\u0131 i\u015fletiyorum.", @@ -865,6 +1862,7 @@ "5": "und auf einmal leckte er eine Tasse neben mir.", "6": "E improvvisamente lecc\u00f2 una tazza da t\u00e8 intorno a me.", "8": "Ten m\u0119\u017cczyzna nagle wyliza\u0142 wszystkie fili\u017canki, kt\u00f3re by\u0142y w pobli\u017cu.", + "9": "e ele de repente lambeu uma x\u00edcara do meu lado.", "10": "\u0418 \u043e\u043d \u0432\u0434\u0440\u0443\u0433 \u043e\u0431\u043b\u0438\u0437\u0430\u043b \u043c\u043e\u044e \u0447\u0430\u0439\u043d\u0443\u044e \u0447\u0430\u0448\u043a\u0443.", "11": "Y de repente comenz\u00f3 a lamer todas las tazas aqu\u00ed.", "13": "15-20 dakika \u00f6nce bir m\u00fc\u015fteri geldi, vitrindeki bardaklar\u0131 yalamaya ba\u015flad\u0131.", @@ -881,6 +1879,7 @@ "5": "Er hat sogar Speichel auf das Sushi bekommen.", "6": "Ha persino lasciati la saliva sul sushi.", "8": "Nawet naplu\u0142 na sushi.", + "9": "Ele at\u00e9 deixou saliva no sushi!", "10": "\u0423 \u043d\u0435\u0433\u043e \u0434\u0430\u0436\u0435 \u0441\u043b\u044e\u043d\u0430 \u043f\u043e\u043f\u0430\u043b\u0430 \u043d\u0430 \u0441\u0443\u0448\u0438.", "11": "Incluso escupi\u00f3 en el sushi", "13": "Sonra su\u015filerin i\u00e7ine falan t\u00fck\u00fcrd\u00fcler.", @@ -897,6 +1896,7 @@ "5": "Der Laden kann zurzeit nicht richtig ge\u00f6ffnet werden.", "6": "Il negozio non pu\u00f2 aprire correttamente ora...", "8": "Teraz restauracja nie mo\u017ce prawid\u0142owo funkcjonowa\u0107.", + "9": "O restaurante n\u00e3o pode abrir normalmente agora...", "10": "\u041c\u0430\u0433\u0430\u0437\u0438\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c\u2026", "11": "Ahora el restaurante no puede funcionar correctamente", "13": "Hijyen sorunu oldu\u011fu i\u00e7in \u015fuan d\u00fckkan\u0131 a\u00e7am\u0131yoruz.", @@ -913,6 +1913,7 @@ "5": "Bitte verhafte ihn!", "6": "Per favore, arrestalo, agente!", "8": "Prosz\u0119 go zaaresztowa\u0107.", + "9": "Por favor prenda ele, policial!", "10": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0430\u0440\u0435\u0441\u0442\u0443\u0439\u0442\u0435 \u0435\u0433\u043e, \u043e\u0444\u0438\u0446\u0435\u0440!", "11": "\u00a1Le arresta, por favor!", "13": "Gere\u011finin yap\u0131lmas\u0131n\u0131 istiyorum memur bey.", @@ -929,6 +1930,7 @@ "5": "Verstanden. Wir werden mit ihm sprechen. Vielleicht darf er sogar nachhause.", "6": "Ho capito. Parleremo con lui. Puoi andare a casa oggi.", "8": "Rozumiem. Porozmawiamy z nim. Mo\u017cesz i\u015b\u0107 do domu.", + "9": "Entendi. A gente vai conversar com ele. Voc\u00ea pode ir pra casa.", "10": "\u042f \u043f\u043e\u043d\u044f\u043b. \u041c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0441 \u043d\u0438\u043c. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0434\u0442\u0438 \u0434\u043e\u043c\u043e\u0439.", "11": "Entiendo. Vamos a hablar con \u00e9l. Puedes volver a la casa.", "13": "Anl\u0131yorum. \u015eimdi ifadesini alaca\u011f\u0131z, daha sonra gerekli i\u015flemleri yapar\u0131z. Siz d\u00fckkan\u0131 kapatt\u0131ysan\u0131z eve gidebilirsiniz.", @@ -945,6 +1947,7 @@ "5": "Ich bitte sie. Officer...", "6": "Ti sto implorando. Agente\u2026", "8": "B\u0142agam Ci\u0119, oficerze.", + "9": "Eu to te implorando. Policial...", "10": "\u042f \u0443\u043c\u043e\u043b\u044f\u044e \u0432\u0430\u0441. \u041e\u0444\u0438\u0446\u0435\u0440\u2026", "11": "\u00a1Te lo ruego, se\u00f1or!", "13": "Te\u015fekk\u00fcrler memur bey, l\u00fctfen gere\u011fini yap\u0131n. Ben gidiyorum kolay gelsin.", @@ -961,6 +1964,7 @@ "5": "Was. Was hast du gesagt habe ich getan?", "6": "Che cosa. Cosa dici che ho fatto?", "8": "Co do diab\u0142a? Co ja zrobi\u0142em?", + "9": "O que? O que voc\u00ea disse que eu fiz??", "10": "\u0427\u0442\u043e. \u0427\u0442\u043e, \u043f\u043e-\u0442\u0432\u043e\u0435\u043c\u0443, \u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c?", "11": "\u00bfQu\u00e9? \u00bfQu\u00e9 co\u00f1o dices? \u00bfQu\u00e9 te he hecho?", "13": "Ne oluyor ya? Ne yapt\u0131m ben?", @@ -977,6 +1981,7 @@ "5": "Und wer bist du?", "6": "E chi sei tu??", "8": "Kim ty jeste\u015b?", + "9": "E quem \u00e9 voc\u00ea?", "10": "\u0418 \u043a\u0442\u043e \u0442\u044b \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e?", "11": "\u00bfY qui\u00e9n eres?", "13": "Ve sen kimsin?", @@ -993,6 +1998,7 @@ "5": "Ich bin Polizist von Revier {0}, {1}.", "6": "Sono un ufficiale della {0} stazione, {1}.", "8": "Jestem {1} z posterunku {0}.", + "9": "Eu sou policial {1} do departamento de pol\u00edcia de {0}.", "10": "\u041a\u0442\u043e \u044f \u0442\u0430\u043a\u043e\u0439? \u0420\u0430\u0437\u0432\u0435 \u044d\u0442\u043e \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e? \u041e\u0444\u0438\u0446\u0435\u0440 \u043f\u043e\u043b\u0438\u0446\u0438\u0438.", "11": "Soy {1} de la estaci\u00f3n {0}.", "13": "Ben kim miyim? Belli olmuyor mu? Polis memuru {1}.", @@ -1009,6 +2015,7 @@ "5": "Du hast einen gro\u00dfen Fehler begangen", "6": "Hai commesso un grave errore, vero??", "8": "Spowodowa\u0142e\u015b bardzo powa\u017cne utrudnienia.", + "9": "Voc\u00ea cometeu um erro grande!", "10": " \u0412\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u043b\u0438 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443", "11": "Has hecho grave error.", "13": "\u00c7ok ciddi bir hata yapt\u0131n.", @@ -1025,6 +2032,7 @@ "5": "Ah-ha. Aber ich w\u00fcrde alles daf\u00fcr tun, um ber\u00fchmt auf Social Media zu werden!", "6": "Uh Huh. Ma per diventare famoso sui social, farei qualsiasi cosa..", "8": "Ta, ale zrobi\u0119 wszystko, co trzeba, by zaistnie\u0107 w mediach spo\u0142eczno\u015bciowych", + "9": "Aham, mas eu faria qualquer coisa para ficar famoso em todas as redes sociais!", "10": "\u0423\u0433\u0443. \u041d\u043e \u044f \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u043b \u0432\u0441\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u043b\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0442\u044f\u0445!", "11": "\u00a1Har\u00eda cualquier cosa para ser famoso!", "13": "H\u0131-h\u0131. Ama sosyal medyada \u00fcnl\u00fc olmak i\u00e7in her\u015feyi yapar\u0131m!\n", @@ -1041,6 +2049,7 @@ "5": "Ist jetzt auch egal.", "6": "Non importa ora!", "8": "To nie ma teraz znaczenia.", + "9": "N\u00e3o importa agora.", "10": "\u041d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043a\u0430\u043a.", "11": "Ya no importa.", "13": "Kim oldu\u011fum belli de\u011fil mi, \u015fuan \u00f6nemli olan benim kim oldu\u011fum mu?", @@ -1057,6 +2066,7 @@ "5": "Du musst verstehen was du falsch getan hast.", "6": "Devi capire il tuo sbaglio.", "8": "Musisz zrozumie\u0107 swoje b\u0142\u0119dy.", + "9": "Voc\u00ea tem que entender o seu erro.", "10": "\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u044e \u043e\u0448\u0438\u0431\u043a\u0443.", "11": "Tienes que entender tu error", "13": "\u0130\u015fledi\u011fin su\u00e7u kabullenmen gerekiyor.", @@ -1073,6 +2083,7 @@ "5": "Ich bin nicht b\u00f6se.", "6": "Non sono cattivo..", "8": "To nie moja wina.", + "9": "Eu n\u00e3o sou uma pessoa ruim.", "10": "\u042f \u043d\u0435 \u0442\u0430\u043a \u0443\u0436 \u043f\u043b\u043e\u0445.", "11": "No es mi culpa", "13": "K\u00f6t\u00fc birisi de\u011filim.", @@ -1089,6 +2100,7 @@ "5": "Und das geht dich auch nichts an.", "6": "E questo non importa anche a te..", "8": "To nie twoja sprawa.", + "9": "Isso tamb\u00e9m n\u00e3o \u00e9 da sua conta.", "10": "\u0418 \u0434\u043b\u044f \u0432\u0430\u0441 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.", "11": "No es tu problema", "13": "Ve bu senin i\u00e7inde \u00f6nemli de\u011fil.", @@ -1105,6 +2117,7 @@ "5": "Ich verstehe das du ber\u00fchmt auf Social Media werden m\u00f6chtest.", "6": "Capisco il tuo desiderio di essere popolare sui social media.", "8": "Wiem, \u017ce chcesz si\u0119 wyr\u00f3\u017cni\u0107 w mediach spo\u0142eczno\u015bciowych.", + "9": "Eu entendo que voc\u00ea quer ser famoso nas redes sociais.", "10": "\u042f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043b\u0438 \u0441\u0442\u0430\u0442\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0432 YouTube.", "11": "Entiendo que quieres ser famoso en las redes sociales", "13": "Ben anlad\u0131m seni, sosyal medyada fenomen olmak istiyorsun.", @@ -1121,6 +2134,7 @@ "5": "Aber du hast es ein wenig falsch verstanden.", "6": "Ma hai capito un po' male..", "8": "Ale zrobi\u0142e\u015b to w z\u0142y spos\u00f3b.", + "9": "Mas voc\u00ea meio que deu uma bola fora.", "10": "\u041d\u043e \u0432\u044b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0448\u0438\u0431\u043b\u0438\u0441\u044c.", "11": "Pero no me entendiste", "13": "Ama biraz yanl\u0131\u015f anlad\u0131n.", @@ -1137,6 +2151,7 @@ "5": "Lasst uns auf dem Polizeirevier sprechen. Es ist noch nicht zu sp\u00e4t.", "6": "Parliamo alla comando. Abbiamo tempo.", "8": "Porozmawiajmy na komisariacie. Jeszcze nie jest za p\u00f3\u017ano.", + "9": "Vamos conversar na delegacia, ainda n\u00e3o \u00e9 tarde demais.", "10": "\u0414\u0430\u0432\u0430\u0439 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0432 \u043f\u043e\u043b\u0438\u0446\u0435\u0439\u0441\u043a\u043e\u043c \u0443\u0447\u0430\u0441\u0442\u043a\u0435. \u0415\u0449\u0435 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u043e\u0437\u0434\u043d\u043e.", "11": "Vamos a hablar en la estaci\u00f3n. No es demasiado tarde.", "13": "Gel karakolda konu\u015fal\u0131m, \u00e7ok ge\u00e7 de\u011fil.", @@ -1153,6 +2168,7 @@ "5": "Mach dir keine Sorgen, jeder macht mal Fehler.", "6": "Tutti falliscono nella vita. Non importa!", "8": "Ka\u017cdy pope\u0142nia b\u0142\u0119dy. Nie przejmuj si\u0119 tym.", + "9": "N\u00e3o se preocupe, todo mundo comete erros.", "10": "\u041d\u0435 \u0432\u043e\u043b\u043d\u0443\u0439\u0441\u044f, \u0432\u0441\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u044e\u0442 \u043e\u0448\u0438\u0431\u043a\u0438.", "11": "Todos cometen errores", "13": "Herkes hata yapar, can\u0131n\u0131 s\u0131kma.", @@ -1169,6 +2185,7 @@ "5": "...stimmt. Tut mir leid.", "6": ".. Sono d'accordo. Mi dispiace.", "8": "...Tak. Przepraszam.", + "9": "...Concordo. Me desculpe.", "10": "...\u042f \u0441\u043e\u0433\u043b\u0430\u0441\u0435\u043d. \u041c\u043d\u0435 \u0436\u0430\u043b\u044c.", "11": "S\u00ed, perd\u00f3n", "13": "...kabul ediyorum, \u00fczg\u00fcn\u00fcm.", @@ -1185,6 +2202,7 @@ "5": "Dann werde ich Sie jetzt verhaften.", "6": "Allora ti arrester\u00f2.", "8": "W takim razie musia\u0142bym Ci\u0119 zaaresztowa\u0107.", + "9": "Ent\u00e3o eu vou te prender.", "10": "\u0422\u043e\u0433\u0434\u0430 \u044f \u0432\u0430\u0441 \u0430\u0440\u0435\u0441\u0442\u0443\u044e.", "11": "As\u00ed, voy a arrestarte.", "13": "O zaman seni tutukluyorum.", @@ -1201,6 +2219,7 @@ "5": "Das ist nicht gut, du machst das falsch.", "6": "Non va bene. Tui hai torto\u2026", "8": "To nie jest dobre. Mylisz si\u0119...", + "9": "Isso n\u00e3o \u00e9 bom, o que voc\u00ea t\u00e1 fazendo t\u00e1 errado...", "10": "\u042d\u0442\u043e \u043d\u0435\u0445\u043e\u0440\u043e\u0448\u043e, \u0432\u044b \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u0435\u0442\u0435 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e...", "11": "No es bueno. Est\u00e1s equivocado", "13": "Bu iyi de\u011fil, hatal\u0131s\u0131n.", @@ -1217,6 +2236,7 @@ "5": "und es muss behoben werden.", "6": "E devono essere corretti ora.", "8": "I trzeba to naprawi\u0107.", + "9": "e precisa ser corrigido.", "10": "\u0418 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c.", "11": "y lo necesita ser corregido ahora.", "13": "ve \u015fimdi d\u00fczelmesi gerekiyor.", @@ -1233,6 +2253,7 @@ "5": "Weil wenn ich es nicht tue, wird niemand darauf reagieren!", "6": "Perch\u00e9 se non lo faccio, nessuno reagir\u00e0 a me!", "8": "Nikt nie b\u0119dzie na mnie reagowa\u0142.", + "9": "Porque se eu n\u00e3o fizer isso, ningu\u00e9m vai me notar!", "10": "\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u044e, \u043d\u0438\u043a\u0442\u043e \u043d\u0430 \u043c\u0435\u043d\u044f \u043d\u0435 \u043e\u0442\u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u0442!", "11": "Porque, si no hago eso, nadie me va a reaccionar.", "13": "\u00c7\u00fcnk\u00fc bunu yapmazsan kimse bana tepki g\u00f6stermeyecek.", @@ -1249,6 +2270,7 @@ "5": "Ich werde immer ignoriert. Ich m\u00f6chte nur, dass jemand auf mich aufmerksam wird.", "6": "Sono sempre ignorato. Quindi voglio che tu reagisca da qualcuno...", "8": "Jestem zawsze ignorowany. Chc\u0119 pozna\u0107 reakcj\u0119 kogokolwiek...", + "9": "Eu sempre sou ignorado. Ent\u00e3o eu quero a rea\u00e7\u00e3o de voc\u00ea de algu\u00e9m...", "10": "\u041c\u0435\u043d\u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044e\u0442. \u042f \u0445\u043e\u0447\u0443 \u0437\u043d\u0430\u0442\u044c \u0440\u0435\u0430\u043a\u0446\u0438\u044e \u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e...", "11": "Siempre me ignoran, entonces quiero de alguien reacci\u00f3n", "13": "Ben her zaman d\u0131\u015fland\u0131m. O y\u00fczden birilerinden tepki bekliyorum ve dikkat \u00e7ekmeye \u00e7al\u0131\u015f\u0131yorum.", @@ -1265,6 +2287,7 @@ "5": "Du hast ein ernsthaftes Verbrechen begangen, Ich werde sie verhaften.", "6": "Quello che hai fatto \u00e8 un grande crimine. ti devo arrestare", "8": "To, co pan zrobi\u0142, jest powa\u017cnym przest\u0119pstwem. Musz\u0119 pana zaaresztowa\u0107.", + "9": "Voc\u00ea cometeu um crime grave, eu vou prender voc\u00ea.", "10": "\u0412\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0438\u043b\u0438 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u043e\u0435 \u043f\u0440\u0435\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435, \u044f \u0432\u0430\u0441 \u0430\u0440\u0435\u0441\u0442\u0443\u044e.", "11": "Cosa que has hecho es delito muy grave. Voy a arrestarte.", "13": "Yapt\u0131\u011f\u0131n b\u00fcy\u00fck bir su\u00e7, seni tutukluyorum.", @@ -1281,6 +2304,7 @@ "5": "Es tut mir leid, es tut mir wirklich leid, Officer...", "6": "Scusa. Mi dispiace, agente...", "8": "Tak, panie oficerze. Przepraszam.", + "9": "Perd\u00e3o. Me desculpe, policial...", "10": "\u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435. \u041c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0436\u0430\u043b\u044c, \u043e\u0444\u0438\u0446\u0435\u0440...", "11": "Perd\u00f3n, se\u00f1or", "13": "Ger\u00e7ekten \u00e7ok \u00fczg\u00fcn\u00fcm memur bey.", @@ -1297,6 +2321,7 @@ "5": "Nein. Wir sind dazu verpflichtet dich von dem Besitzer warnen zu lassen.", "6": "No. Siamo obbligati ad avvisarti per conto del proprietario.", "8": "Nie, nie. Jeste\u015bmy zobowi\u0105zani do ostrze\u017cenia pana w imieniu w\u0142a\u015bciciela restauracji.", + "9": "N\u00e3o. Temos a obriga\u00e7\u00e3o de avisar voc\u00eas em nome do propriet\u00e1rio.", "10": "\u041d\u0435\u0442. \u041c\u044b \u043e\u0431\u044f\u0437\u0430\u043d\u044b \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434\u0438\u0442\u044c \u0432\u0430\u0441 \u043e\u0442 \u0438\u043c\u0435\u043d\u0438 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430.", "11": "No, tenemos que advertirte en nombre de propietario.", "13": "Hay\u0131r \u00f6nemli, sizi uyamakla y\u00fck\u00fcml\u00fcy\u00fcz, ve yapt\u0131\u011f\u0131n bir su\u00e7.", @@ -1313,6 +2338,7 @@ "5": "Wir sind hier, weil der Besitzer 110 gew\u00e4hlt hat.", "6": "Siamo venuti qui dopo che il proprietario ha chiamato il numero d'emergenza.", "8": "Jeste\u015bmy tutaj po tym, jak w\u0142a\u015bciciel zadzwoni\u0142 na 911.", + "9": "Viemos aqui porque o dono ligou para 190.", "10": "\u041c\u044b \u043e\u0442\u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043d\u0430 \u0432\u044b\u0437\u043e\u0432, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043f\u043e\u0437\u0432\u043e\u043d\u0438\u043b \u0432 911.", "11": "Llegamos aqu\u00ed porque propietario nos llam\u00f3.", "13": "Neden b\u00f6yle bir \u015fey yapt\u0131n? ", @@ -1329,6 +2355,7 @@ "5": "Wenn er und ich uns \u00fcber das Problem unterhalten, kann ich \u00fcberzeugt werden. Aber...", "6": "So che se gli parlo, ma...", "8": "Gdybym z nim rozmawia\u0142, zrozumia\u0142bym.", + "9": "E se eu e ele conversarmos sobre isso, eu posso ser convencido, mas...", "10": "\u0415\u0441\u043b\u0438 \u043c\u044b \u0441 \u043d\u0438\u043c \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e\u0431 \u0438\u043d\u0446\u0438\u0434\u0435\u043d\u0442\u0435, \u044f \u0441\u043c\u043e\u0433\u0443 \u0431\u044b\u0442\u044c \u0443\u0431\u0435\u0436\u0434\u0435\u043d. \u041d\u043e...", "11": "Sabr\u00eda, si hablar con \u00e9l", "13": "D\u00fckkan\u0131n sahibi ile konu\u015fursak anla\u015fabiliriz,", @@ -1345,6 +2372,7 @@ "5": "Ich verstehe nicht, warum ich euch das sagen sollte. Ohne Spa\u00df!", "6": "Non vedo perch\u00e9 devo dirvelo ragazzi. Non scherzare!", "8": "Nie wiem, dlaczego musz\u0119 wam to powiedzie\u0107. Chyba sobie \u017cartujecie!", + "9": "Eu n\u00e3o vejo motivo de falar nada pra voc\u00eas, eu heim!", "10": "\u042f \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u043f\u043e\u0447\u0435\u043c\u0443 \u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u0432\u0430\u043c, \u0440\u0435\u0431\u044f\u0442\u0430. \u041d\u0435 \u0448\u0443\u0442\u0438!", "11": "No s\u00e9, por qu\u00e9 tengo que decirlo. No bromeen.", "13": "yapt\u0131\u011f\u0131m \u015feyin sizin ile alakas\u0131 yok! Bo\u015fverin...", @@ -1361,6 +2389,7 @@ "5": "Der Laden kann zurzeit nicht ge\u00f6ffnet werden.", "6": "Il negozio non pu\u00f2 essere aperto ora.", "8": "Ten sklep tymczasowo nie mo\u017ce by\u0107 otwarty na dzia\u0142alno\u015b\u0107.", + "9": "A loja n\u00e3o pode mais abrir agora.", "10": "\u041c\u0430\u0433\u0430\u0437\u0438\u043d \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044c\u0441\u044f.", "11": "Este restaurante no debe estar abierto por un tiempo", "13": "Restoran \u015fuan i\u00e7in a\u00e7\u0131lm\u0131yor.", @@ -1377,6 +2406,7 @@ "5": "Du musst die Verantwortung daf\u00fcr \u00fcbernehmen.", "6": "Devi assumerti la responsabilit\u00e0 di questo.", "8": "Musisz wzi\u0105\u0107 za to odpowiedzialno\u015b\u0107.", + "9": "Voc\u00ea tem que tomar responsabilidade por isso.", "10": "\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u0437\u044f\u0442\u044c \u043d\u0430 \u0441\u0435\u0431\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u044d\u0442\u043e.", "11": "Tienes que asumir la responsabilidad de eso.", "13": "Bunun sorumlulu\u011funu almal\u0131s\u0131n.", @@ -1393,6 +2423,7 @@ "5": "Warum...Warum...", "6": "Perch\u00e8 perch\u00e8\u2026", "8": "Dlaczego...", + "9": "Por qu\u00ea? Por qu\u00ea?", "10": "\u041f\u043e\u0447\u0435\u043c\u0443?\u2026\u041f\u043e\u0447\u0435\u043c\u0443?\u2026", "11": "Por qu\u00e9...", "13": "Neden... Nedennn...", @@ -1409,6 +2440,7 @@ "5": "Ich werde dich jetzt verhaften.", "6": "Sei in arresto.", "8": "Jest pan aresztowany za utrudnianie pracy.", + "9": "Eu vou te prender agora.", "10": "\u042f \u0442\u0435\u0431\u044f \u0441\u0435\u0439\u0447\u0430\u0441 \u0430\u0440\u0435\u0441\u0442\u0443\u044e.", "11": "Voy a arrestarte ahora", "13": "\u015eimdi seni tutuklayaca\u011f\u0131m.", @@ -1418,13 +2450,85 @@ "19": "Pid\u00e4t\u00e4n sinut nyt.", "20": "Dabar j\u016bs esate suimamas." }, + "HitAndRunTalk1": { + "0": "\u3053\u3093\u306b\u3061\u306f\u3002\u901a\u5831\u8005\u306e\u65b9\u3067\u3059\u304b?", + "2": "\u60a8\u597d\uff0c\u8acb\u554f\u662f\u4f60\u6253\u7684110\u55ce\uff1f", + "3": "Hello. Are you caller to 911?", + "5": "Hallo, haben Sie uns gerufen?", + "6": "Ciao. Stai chiamando il nue 112?", + "8": "Witam. Czy to ty dzwoni\u0142e\u015b na 911?", + "9": "Ol\u00e1, foi voc\u00ea que ligou para 190?", + "10": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e \u043d\u0430\u0435\u0437\u0434\u0435 \u0438 \u0431\u0435\u0433\u0441\u0442\u0432\u0435 1", + "13": "Merhabalar, 112 acil \u00e7a\u011fr\u0131 merkezi, nas\u0131l yard\u0131mc\u0131 olabiliriz?", + "14": "Dobry den, volate na 911?", + "16": "Hej, var det du som ringde 112?", + "20": "Sveiki, ar j\u016bs skambinote 911?" + }, + "HitAndRunTalk2": { + "0": "\u306f\u3044\u3002\u3053\u3053\u3092\u6b69\u3044\u3066\u3044\u305f\u3089\u8eca\u304c\u3042\u306e\u4eba\u3092\u306f\u306d\u305f\u3093\u3067\u3059\u3002", + "2": "\u5c0d\u7684\uff0c\u6211\u5728\u8d70\u8def\u7684\u6642\u5019\uff0c\u4e00\u8f1b\u8eca\u5c31\u7a81\u7136\u649e\u904e\u4f86\u4e86", + "3": "Yes. A car hit him when I was walking here.", + "5": "Ja, das war ich. Ein Fahrzeug hat ihn gerammt w\u00e4hrend ich hier vorbei gelaufen bin.", + "6": "S\u00cc. Una macchina l'ha investito mentre stavo camminando qui", + "8": "Tak. Samoch\u00f3d go potr\u0105ci\u0142, kiedy tutaj szed\u0142em.", + "9": "Sim. Um carro bateu nele quando eu estava passando por aqui.", + "10": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e \u043d\u0430\u0435\u0437\u0434\u0435 \u0438 \u0431\u0435\u0433\u0441\u0442\u0432\u0435 2", + "13": "Merhabalar, az \u00f6nce bir araca \u00e7arpt\u0131lar ve ara\u00e7ta a\u011f\u0131r hasar olu\u015ftu. Daha sonras\u0131nda ka\u00e7t\u0131lar.", + "14": "Ano, kdyz jsem sem sel kolem tak ho srazilo auto.", + "16": "Ja. Det var en bil som k\u00f6rde p\u00e5 honom.", + "20": "Taip, ka\u017ekokia ma\u0161ina partrenk\u0117 j\u012f, kol a\u0161 \u010dia \u0117jau." + }, + "HitAndRunTalk3": { + "0": "\u8eca\u4e21\u306e\u7279\u5fb4\u306f\u5206\u304b\u308a\u307e\u3059\u304b?", + "2": "\u4f60\u8a18\u5f97\u90a3\u8f1b\u8eca\u7684\u8eca\u8f1b\u7279\u5fb5\u55ce\uff1f", + "3": "Do you remember the features of the vehicle?", + "5": "Wissen Sie noch wie das Fahrzeug aussah?", + "6": "Ricordi le caratteristiche del veicolo?", + "8": "Czy pami\u0119tasz, jaki to by\u0142 pojazd?", + "9": "Voc\u00ea se lembra como era o ve\u00edculo?", + "10": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e \u043d\u0430\u0435\u0437\u0434\u0435 \u0438 \u0431\u0435\u0433\u0441\u0442\u0432\u0435 3", + "13": "Arac\u0131n \u00f6zelliklerini veya plakas\u0131n\u0131 hat\u0131rl\u0131yor musunuz?", + "14": "Pomatujete si jak to vozidlo vypadalo?", + "16": "Kommer du ih\u00e5g n\u00e5got fr\u00e5n bilen? T.ex. f\u00e4rg eller reg. nummer?", + "20": "Ar prisiminate, kaip atrod\u0117 automobilis?" + }, + "HitAndRunTalk4": { + "0": "\u78ba\u304b\u3001\u30ca\u30f3\u30d0\u30fc\u306f{0}\u3067\u3001\u8272\u306f{1}\u3067\u3057\u305f\u3002", + "2": "\u6211\u8a18\u5f97\u8eca\u724c\u597d\u50cf\u662f\u865f\u78bc\u662f {0} \uff0c\u662f{1}\u7684\u8eca\u5b50\u3002", + "3": "I believe the license number was {0} and the color was {1}.", + "5": "Ich glaube, das Kennzeichen war {0}. Das Fahrzeug war {1}.", + "6": "Credo che il numero di licenza fosse {0} e il colore fosse {1}.", + "8": "Pami\u0119tam, \u017ce numer rejestracyjny to {0}, a kolor to {1}.", + "9": "Eu acho que a placa era {0} e a cor era {1}", + "10": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e \u043d\u0430\u0435\u0437\u0434\u0435 \u0438 \u0431\u0435\u0433\u0441\u0442\u0432\u0435 4", + "13": "Evet evet plakas\u0131n\u0131 ald\u0131k, {0}. Ve ara\u00e7 {1} renkiydi.", + "14": "Myslim, ze licencni cislo bylo {0} a barva byla {1}.", + "16": "Jag tror att reg. numret var {0} och den var {1}.", + "20": "Man rodos, kaip atsimenu, tai buvo {1} automobilis, o valstybinis numeris buvo {0}" + }, + "HitAndRunTalk5": { + "0": "\u5206\u304b\u308a\u307e\u3057\u305f\u3002\u6b8b\u308a\u306f\u8b66\u5bdf\u3067\u8abf\u67fb\u3057\u307e\u3059\u3002", + "2": "\u77ad\u89e3\uff0c\u63a5\u4e0b\u4f86\u6211\u5011\u8b66\u65b9\u6703\u9032\u884c\u8abf\u67e5\u7684\u3002", + "3": "I understand.The rest will be investigated by the police.", + "5": "Alles klar. Vielen Dank, wir werden uns drum k\u00fcmmern.", + "6": "Capisco. Il resto sar\u00e0 indagato dalla polizia.", + "8": "Rozumiem. Reszta zostanie rozpatrzona przez policj\u0119.", + "9": "Entendi. Pode deixar que o resto vai ser investigado pela pol\u00edcia.", + "10": "\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e \u043d\u0430\u0435\u0437\u0434\u0435 \u0438 \u0431\u0435\u0433\u0441\u0442\u0432\u0435 5", + "13": "Tamamd\u0131r te\u015fekk\u00fcrler, polis ekipleri gerekli i\u015flemleri yapacakt\u0131r.", + "14": "Rozumim, zbytek bude vysetrovat policie.", + "16": "Jag f\u00f6rst\u00e5r. Vi startar en utredning om smitning.", + "20": "Supratau, d\u0117koju. Toliau visk\u0105 i\u0161spr\u0119s policija." + }, "ContextMenuTitle": { "0": "\u7dcf\u5408\u30e1\u30cb\u30e5\u30fc", "2": "\u9078\u55ae", "3": "Context Menu", + "4": "Menu contextuel", "5": "Kontext Men\u00fc", "6": "Menu", "8": "Menu ", + "9": "Menu de Contexto", "10": "\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e", "11": "Menu", "13": "Durum Men\u00fcs\u00fc", @@ -1438,9 +2542,11 @@ "0": "\u8a00\u8a9e\u9078\u629e", "2": "\u9078\u64c7\u8a9e\u8a00", "3": "Language Select", + "4": "Menu de s\u00e9lection de la langue", "5": "Sprachen Auswahl", "6": "Seleziona lingua", "8": "Wyb\u00f3r j\u0119zyka ", + "9": "Sele\u00e7\u00e3o de Idioma", "10": "\u041c\u0435\u043d\u044e \u0432\u044b\u0431\u043e\u0440\u0430 \u044f\u0437\u044b\u043a\u0430", "11": "Selecci\u00f3n de idioma", "13": "Dil Se\u00e7me", @@ -1454,9 +2560,11 @@ "0": "\u30b3\u30fc\u30eb\u30a2\u30a6\u30c8\u4e00\u89a7", "2": "\u6848\u4ef6\u9078\u55ae", "3": "Callouts List", + "4": "Liste des appels", "5": "Einsatz Liste", "6": "Lista chiamate", "8": "Lista zg\u0142osze\u0144 ", + "9": "Lista de Chamados", "10": "\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u044b\u0437\u043e\u0432\u043e\u0432", "11": "Lista de llamadas", "13": "\u0130hbar Listesi", @@ -1470,8 +2578,11 @@ "0": "\u4ea4\u901a\u64cd\u4f5c\u30e1\u30cb\u30e5\u30fc", "2": "\u4ea4\u901a\u7ba1\u5236", "3": "Traffic Control", + "4": "Menu Interception routi\u00e8re", + "5": "Verkehrskontrolle", "6": "Controllo del traffico", "8": "Kontrola ruchu", + "9": "Controle de Tr\u00e1fego", "10": " \u041c\u0435\u043d\u044e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0440\u043e\u0436\u043d\u044b\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c", "11": "Control de tr\u00e1fico", "13": "Trafik Kontrol", @@ -1483,177 +2594,220 @@ "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u8a2d\u7f6e", "2": "\u653e\u7f6e ~o~ \u4e09\u89d2\u9310 ~s~", "3": "Place ~o~pylons~s~", + "5": "Platziere ~o~Pylonen~s~", "6": "Posiziona blocco", "8": "Postaw ~o~pacho\u0142ki~s~", + "9": "Coloque ~o~cones~s~", "10": "\u041c\u0435\u043d\u044e \"\u0417\u043d\u0430\u043a\u043e\u0432\"", "11": "Poner los ~o~pilones~s~", "13": "~o~Dubalar\u0131~s~ yerle\u015ftir", "14": "Umistete ~o~dopravni kuzele~s~", - "16": "Placera ~o~pyloner~s~", + "16": "Placera ~o~koner~s~", "20": "Pad\u0117ti ~o~k\u016bg\u012f~s~" }, "PylonTypeItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u7a2e\u985e", "2": "~o~ \u4e09\u89d2\u9310 ~s~ \u7a2e\u985e", "3": "Type of ~o~pylons~s~", + "5": "Arten von ~o~Pylonen~s~", "6": "Tipo di blocco", "8": "Rodzaj ~p~pacho\u0142k\u00f3w~s~", + "9": "Tipos de ~o~cones~s~", "10": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0442\u0438\u043f\u0430 \u043a\u043e\u043d\u0443\u0441\u043e\u0432", "11": "Categor\u00eda de ~p~pilones~s~", "13": "~o~Duba~s~ t\u00fcr\u00fc", "14": "Typ ~p~kuzelu~s~", + "16": "Typ av ~o~kon~s~", "20": "~o~K\u016bgi\u0173~s~ r\u016b\u0161ys" }, "PylonFreezeItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092\u56fa\u5b9a\u3059\u308b", "2": "\u51cd\u7d50 ~o~ \u4e09\u89d2\u9310 ~s~", "3": "Freeze ~o~pylons~s~", + "5": "Friere die ~o~Pylonen~s~ ein", "6": "Congela cono stradale ", "8": "Zamr\u00f3\u017a ~o~pacho\u0142ki~s~", + "9": "Pare o ~o~cone~s~", "10": "\u0417\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0443\u0441\u044b", "11": "Congelar los ~o~pilones~s~", "13": "~o~Dubalar\u0131~s~ sabitle.", "14": "Zmrazit ~o~dopravni kuzele~s~", + "16": "Frys ~o~koner~s~", "20": "Sustingdinti ~o~k\u016bgius~s~" }, "StartSetPylonPos": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u8a2d\u7f6e\u958b\u59cb\u5834\u6240\u3092\u6307\u5b9a", "2": "\u4e00\u7d44 ~o~\u4e09\u89d2\u9310~s~ \u958b\u59cb\u4f4d\u7f6e", "3": "Set for ~o~pylons~s~ start position", + "5": "Gebe den Startpunkt f\u00fcr die Installation von ~o~Pylonen~s~ an", "6": "Impostare la posizione iniziale del blocco", "8": "Ustaw ~o~pacho\u0142ki~s~ w pozycji pocz\u0105tkowej", + "9": "Escolha a posi\u00e7\u00e3o inicial dos ~o~cones~s~", "10": "\u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043d\u0443\u0441\u044b \u041f\u043e\u0437...", "11": "Establecer los ~o~pilones~s~ en posici\u00f3n de inicio", "13": "~o~Dubalar~s~ i\u00e7in ba\u015flang\u0131\u00e7 pozisyonu ayarla", "14": "Nastavte pro ~o~dopravni kuzele~s~ pocatecni pozici", + "16": "S\u00e4tt ~o~konernas~s~ start position", "20": "Nustatyti ~o~k\u016bgi\u0173~s~ pradin\u0119 viet\u0105" }, "ResetPylonPos": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u4f4d\u7f6e\u3092\u4fee\u6b63", "2": "\u66f4\u63db ~o~ \u4e09\u89d2\u9310 ~s~ \u4f4d\u7f6e", "3": "Change for ~o~pylons~s~ positions", + "5": "\u00c4ndere die Position der ~o~Pylonen~s~", "6": "Modifica per le posizioni cono stradale", "8": "Zmie\u0144 pozycj\u0119 ~o~pacho\u0142k\u00f3w~s~ ", + "9": "Mude a posi\u00e7\u00e3o dos ~o~cones~s~", "10": "\u0421\u0431\u0440\u043e\u0441 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0443\u0441\u043e\u0432", "11": "Cambiar posici\u00f3n de los ~o~pilones~s~ ", "13": " ~o~Dubalar\u0131n~s~ pozisyonunu de\u011fi\u015ftirin", "14": "Zmena ~o~dopravnich kuzelu~s~ a jejich pozice", + "16": "Byt ~o~konernas~s~ position", "20": "Per naujo pakeisti ~o~k\u016bgi\u0173~s~ r\u016b\u0161\u012f" }, "EndSetPylonPos": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u7d42\u4e86\u4f4d\u7f6e\u3092\u6307\u5b9a", "2": "\u4e00\u7d44 ~o~ \u4e09\u89d2\u9310 ~s~ \u7d50\u675f\u4f4d\u7f6e", "3": "Set for ~o~pylons~s~ end position", + "5": "Gebe den Endpunkt f\u00fcr die Installation von ~o~Pylonen~s~ an", "6": "Imposta la posizione finale del cono stradale", "8": "Ustaw ~o~pacho\u0142ki~s~ w pozycji ko\u0144cowej", + "9": "Escolha a posi\u00e7\u00e3o final dos ~o~cones~s~", "10": "\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043d\u0443\u0441\u043e\u0432", "11": "Establecer los ~o~pilones~s~ en posici\u00f3n final", "13": "~o~Dubalar~s~ i\u00e7in biti\u015f pozisyonu ayarla\n", "14": "Nastavte pro ~o~dopravni kuzele~s~ koncovou polohu", + "16": "V\u00e4lj ~o~konernas~s~ slut position", "20": "Nustatyti ~o~k\u016bgi\u0173~s~ baigtin\u0119 viet\u0105" }, "PylonCountItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u672c\u6570", "2": "\u4e00\u7d44 ~o~\u4e09\u89d2\u9310~s~ \u6578\u91cf", "3": "Set count of ~o~pylons~s~", + "5": "Gebe die Anzahl von ~o~Pylonen~s~ an", "6": "Imposta il numero dei coni stradale", "8": "Ustaw ilo\u015b\u0107 ~o~pacho\u0142k\u00f3w~s~", + "9": "Defina a quantidade de ~o~cones~s~", "10": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0437\u043d\u0430\u043a\u043e\u0432", "11": "Establecer el n\u00famero de ~o~pilones~s~", "13": "~o~Dubalar\u0131n~s~ say\u0131s\u0131n\u0131 ayarla", "14": "Nastavte pocet ~o~kuzelu~s~", + "16": "V\u00e4lj antal ~o~koner~s~", "20": "Nustatyti ~o~k\u016bgi\u0173~s~ kiek\u012f" }, "PlacePylonsItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092\u8a2d\u7f6e", "2": "\u653e\u7f6e ~o~ \u4e09\u89d2\u9310 ~s~", "3": "Place ~o~pylons~s~", + "5": "Platziere ~o~Pylon~s~", "6": "Posiziona cono stradale ", "8": "Postaw ~o~pacho\u0142ki~s~", + "9": "Coloque os ~o~cones~s~", "10": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u043a\u043e\u0432", "11": "Poner los ~o~pilones~s~", "13": "~o~Dubalar\u0131~s~ yerle\u015ftir", "14": "Umistete ~o~dopravni kuzele~s~", + "16": "Placera ut ~o~koner~s~", "20": "Pad\u0117ti ~o~k\u016bg\u012f~s~" }, "ResetPylonItem": { "0": "~r~\u30ea\u30bb\u30c3\u30c8~s~", "2": "~r~ \u91cd\u7f6e ~s~", "3": "~r~Reset~s~", + "5": "~r~Zur\u00fccksetzen~s~", "6": "Ripristina ", "8": "~r~Resetuj~s~", + "9": "~r~Recome\u00e7ar~s~", "10": "\u0421\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043a\u043e\u043d\u0443\u0441\u043e\u0432 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435", "11": "~r~Reiniciar~s~", "13": "~r~S\u0131f\u0131rla~s~", "14": "~r~Odstranis dopravni kuzele~s~", + "16": "~r~\u00c5terst\u00e4ll~s~", "20": "~r~Perrinkti~s~" }, "PlacePylonItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092~b~\u7f6e\u304f~s~", "2": "~b~ \u653e\u7f6e ~s~ ~o~ \u4e09\u89d2\u9310 ~s~", "3": "~b~Place~s~ the ~o~pylon~s~", + "5": "~b~Platziere~s~ den ~o~Pylon~s~", "6": "Posiziona blocco stradale ", "8": "~b~Postaw~s~ ~o~pacho\u0142ek~s~", + "9": "~b~Coloque~s~ os ~o~cones~s~", "10": "~b~\u041c\u0435\u0441\u0442\u043e~s~ \u0434\u043b\u044f ~o~\u0437\u043d\u0430\u043a\u043e\u0432~s~", "11": "~b~Poner~s~ el ~o~pil\u00f3n~s~", "13": "~o~Dubay\u0131~s~ ~b~yerle\u015ftir~s~", "14": "~b~Umistete~~o~kuzel~s~", + "16": "~b~S\u00e4tt ner~s~ ~o~konerna~s~", "20": "~b~Pad\u0117ti~s~ ~o~k\u016bgius~s~" }, "CarryPylonItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092~b~\u904b\u3076~s~", "2": "~b~ \u643a\u5e36 ~s~ ~o~ \u4e09\u89d2\u9310 ~s~", "3": "~b~Carry~s~ the ~o~pylon~s~", + "5": "~b~Trage~s~ den ~o~Pylon~s~", "6": "Trasporta cono stradale", "8": "~b~We\u017a~s~ ~o~pacho\u0142ek~s~", + "9": "~b~Carregue~s~ os ~o~cones~s~", "10": "~b~\u0423\u0441\u0442\u043e\u043d\u043e\u0432\u0438\u0442\u044c ~s~ \u043d\u0430 ~o~\u043a\u043e\u043d\u0443\u0441~s~", "11": "~b~Llevar~s~ el ~o~pil\u00f3n~s~", "13": "~o~Dubay\u0131~s~ ~b~ta\u015f\u0131~s~", "14": "~b~Prenesete~~kuzel~s~", + "16": "~b~Plocka upp~s~ ~o~konen~s~", "20": "~b~Ne\u0161tis~s~ ~o~k\u016bg\u012f~s~" }, "DeletePylonItem": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092~r~\u524a\u9664~s~", "2": "~r~ \u522a\u9664 ~s~ ~o~ \u4e09\u89d2\u9310 ~s~ \u3002", "3": "~r~Delete~s~ ~o~Pylon~s~", + "5": "~r~L\u00f6sche~s~ den ~o~Pylon~s~", "6": "Elimina cono stradale ", "8": "~r~Usu\u0144~s~ ~o~Pacho\u0142ek~s~", + "9": "~r~Apague o~s~ ~o~Cone~s~", "10": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0443\u0441\u044b", "11": "~r~Suprimir~s~ el ~o~pil\u00f3n~s~", "13": "~o~Dubay\u0131~s~ ~r~sil~s~.", "14": "~r~Odstranit~s~ ~o~dopravni kuzele~s~.", + "16": "~r~Ta Bort~s~ ~o~Konen~s~", "20": "~r~I\u0161trinti~s~ ~o~k\u016bg\u012f~s~." }, "NearestPylon": { "0": "\u6700\u3082\u8fd1\u304f", "2": "\u6700\u8fd1\u7684", "3": "Nearest", + "5": "N\u00e4chster", "6": "Pi\u00f9 vicino", "8": "Najbli\u017cszy", + "9": "Mais pr\u00f3ximo", "10": "\u0411\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u043a\u043e\u043d\u0443\u0441", "11": "M\u00e1s cercano", "13": "En yak\u0131n", "14": "nejblizsi", + "16": "N\u00e4rmaste", "20": "Ar\u010diausias" }, "AllPylon": { "0": "\u5168\u3066", "2": "\u5168\u90e8", "3": "All", + "5": "Alle", "6": "Tutti coni stradale ", "8": "Wszystkie", + "9": "Todos", "10": "\u0412\u0441\u0435 \u043a\u043e\u043d\u0443\u0441\u044b", "11": "Todo", "13": "T\u00fcm\u00fc", "14": "vsechny", + "16": "Alla", "20": "Visi" }, "LanguageSelectItem": { "0": "\u4f7f\u7528\u3059\u308b~b~\u8a00\u8a9e\u3092\u5909\u66f4\u3059\u308b~s~", "2": "\u4f7f\u7528 ~b~ \u8a9e\u8a00\u5df2\u8b8a\u66f4 ~s~", "3": "Change ~b~Language to use~s~", + "5": "\u00c4nder die ~b~Sprache~s~", "6": "Cambia ~b~Lingua da usare~s~", "8": "Zmie\u0144 ~b~j\u0119zyk, by go u\u017cy\u0107~s~", + "9": "Mude ~b~o Idioma~s~", "10": "\u0412\u044b\u0431\u043e\u0440 \u044f\u0437\u044b\u043a\u0430", "11": "Cambia ~b~el idioma para usarlo~s~", "13": "~g~Kullanaca\u011f\u0131n\u0131z dili~g~ ~y~se\u00e7in.~g~", @@ -1670,6 +2824,7 @@ "5": "~g~Starte Einsatz~s~", "6": "~g~Avvia chiamata~s~", "8": "~g~Rozpocznij wezwanie~s~", + "9": "~g~Comece o chamado~s~", "10": "\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u044b\u043d\u043e\u0441\u043e\u043a", "11": "~g~Empeza una llamada~s~", "13": "~g~\u0130hbar\u0131 Ba\u015flat~s~", @@ -1686,6 +2841,7 @@ "5": "Algorithmus", "6": "Algoritmo", "8": "Algorytm ", + "9": "Algoritmo", "10": "\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c", "11": "Algoritmo", "13": "Algoritma", @@ -1699,24 +2855,30 @@ "0": "\u4ea4\u901a\u64cd\u4f5c\u30e1\u30cb\u30e5\u30fc", "2": "\u4ea4\u901a\u7ba1\u5236\u9078\u55ae", "3": "Traffic Control Menu", + "5": "Verkehrskontrollen Men\u00fc", "6": "Men\u00f9 di controllo del traffico", "8": " Menu Kontroli Ruchu", + "9": "Menu de Controle de Tr\u00e1fego", "10": "\u041c\u0435\u043d\u044e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0440\u043e\u0436\u043d\u044b\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c", "11": "Control de tr\u00e1fico menu ", "13": "Trafik Kontrol Men\u00fcs\u00fc", "14": "Nabidka rizeni dopravy", + "16": "Trafik Kontroll Meny", "20": "Eismo kontrol\u0117s meniu" }, "PylonMenuTitle": { "0": "\u30d1\u30a4\u30ed\u30f3\u8a2d\u7f6e", "2": "\u4e09\u89d2\u9310\u9078\u55ae", "3": "Pylon Menu", + "5": "Pylonen Men\u00fc", "6": "Men\u00f9 cono stradale", "8": "Menu pacho\u0142k\u00f3w", + "9": "Menu de Cone", "10": "\u041c\u0435\u043d\u044e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0443\u0441\u0430\u043c\u0438", "11": "Pil\u00f3n Menu", "13": "Duba Men\u00fcs\u00fc", "14": "Nabidka kuzelu", + "16": "Kon Meny", "20": "K\u016bgi\u0173 meniu" }, "LanguageSelectItemDesc": { @@ -1726,6 +2888,7 @@ "5": "Wechsle ~b~DynamicLSPDFR~s~'s ~o~Sprache~s~.", "6": "Cambia la ~b~LSPDFR~s~ dinamica di ~Lingua~s~.", "8": "Zmie\u0144 ~o~j\u0119zyk~s~", + "9": "Mude o ~o~Idioma do~s~'s ~b~DynamicLSPDFR~s~.", "10": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c ~b~DynamicLSPDFR~s~'s ~o~\u042f\u0437\u044b\u043a~s~.", "11": "Cambiar ~o~idioma~s~", "13": "~b~DynamicLSPDFR'\u0131n~s~ ~o~dilini~s~ ~y~de\u011fi\u015ftirin.~s~", @@ -1742,6 +2905,7 @@ "5": "Starte ~b~DynamicLSPDFR~s~'s ~o~Einsatz~s~.", "6": "Avvia i ~o~Callout~s~ di ~b~DynamicLSPDFR~s~.", "8": "Rozpocznij ~o~wezwanie~s~ ~b~z tego pluginu~s~'s.", + "9": "Comece os ~o~chamados do~s~'s ~b~DynamicLSPDFR~s~.", "10": "\u041d\u0430\u0447\u0430\u043b\u043e ~b~DynamicLSPDFR~s~'s ~o~\u0412\u044b\u0437\u043e\u0432\u043e\u0432~s~.", "11": "Empezar ~b~Dynamic LSPDFR~s~ ~o~llamada~s~.", "13": "Bir ~g~ihbar ba\u015flat\u0131n.~s~", @@ -1758,6 +2922,7 @@ "5": "\u00c4ndere den ~o~Zufalls Zahlen Generator~s~ mit ~b~DynamicLSPDFR~s~.", "6": "Cambia l'~o~Algoritmo del numero casuale~s~ usando ~b~DynamicLSPDFR~s~.", "8": "Zmie\u0144 t ~o~algorytm losowych liczb~s~ za pomoc\u0105 ~b~Dynamic LSPDFR~s~.", + "9": "Mude o ~o~N\u00famero do algoritmo aleat\u00f3rio~s~ usando ~b~DynamicLSPDFR~s~.", "10": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 ~o~\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c ~s~ \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e~b~DynamicLSPDFR~s~.", "11": "Cambiar el ~o~algoritmo de n\u00fameros aleatorios~s~ usando~b~Dynamic LSPDFR~s~.", "13": "~b~Rastgele say\u0131 algoritmas\u0131n\u0131~s~ de\u011fi\u015ftirin.", @@ -1771,12 +2936,15 @@ "0": "~b~\u4ea4\u901a~s~\u3092\u5236\u5fa1\u3059\u308b\u305f\u3081\u306e~g~\u30c4\u30fc\u30eb~s~", "2": "~g~ \u4ea4\u901a ~s~ \u7ba1\u5236\u5de5\u5177\u3002", "3": "~g~Tools~s~ of control ~g~traffic~s~.", + "5": "Verkehrskontrollwerkzeug", "6": "Strumenti di controllo del traffico.", "8": "~g~Narz\u0119dzia~s~ kontroli ~g~ruchu~s~.", + "9": "~g~Ferramentas~s~ de controle de ~g~tr\u00e1fego~s~.", "10": "\u041c\u0435\u043d\u044e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0440\u043e\u0436\u043d\u044b\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435", "11": "~g~Herramientas~s~ de ~g~control de tr\u00e1fico~s~.", "13": "~g~Trafik kontrol~s~ ~o~ara\u00e7lar\u0131~s~.", "14": "~g~Nastroje~s~ rizeni ~g~dopravy~s~.", + "16": "~g~Verktyg~s~ f\u00f6r att styra ~g~trafik~s~.", "20": "~g~Eismo~s~ kontrol\u0117s ~g~\u012frankiai~s~" }, "LanguageMenuDesc": { @@ -1786,6 +2954,7 @@ "5": "W\u00e4hle ~b~die Sprache~s~ die du m\u00f6chtest.\nFalls du ~g~Zufalls \u00dcbersetzung~s~, bitte w\u00e4hle ~o~\"Custom''~s~ aus.", "6": "Lingua Men\u00f9", "8": "Wybierz ~b~j\u0119zyk~s~, kt\u00f3rego chcesz u\u017cywa\u0107.\nJe\u017celi chcesz zmieni\u0107 ~g~niestandardowe t\u0142umaczenie~s~, prosz\u0119 wybierz ~o~\"Niestandardowe\"~s.", + "9": "Escolha ~b~o idioma~s~ que voc\u00ea quer.\nSe voc\u00ea quer mudar para ~g~Tradu\u00e7\u00f5es customizadas~s~, selecione ~o~\"Customizado\"~s~.", "10": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u044f\u0437\u044b\u043a\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u043d\u044e", "11": "Elegir ~b~el idioma~s~, que quieres usar.\nSi quieres cambiar ~g~traducci\u00f3n personalizada~s~, elige ~o~\"personalizada\"~s.", "13": "~g~Kullanmak istedi\u011fin dili~s~ se\u00e7.", @@ -1799,8 +2968,10 @@ "0": "~h~~y~\u3010\u6ce8\u610f\u3011~s~~h~\n~r~\u5272\u308a\u5f53\u3066\u3089\u308c\u3066\u3044\u306a\u3044\u30ad\u30fc\u306e\u7ffb\u8a33\u306b\u306f\u81ea\u52d5\u7684\u306b\u82f1\u8a9e\u7ffb\u8a33\u304c\u9069\u7528\u3055\u308c\u307e\u3059\u3002~s~", "2": "~h~~y~ \u3010\u6ce8\u610f\u3011 ~s~~h~\n~r~ \u5c1a\u672a\u7ffb\u8b6f\u4e4b\u8a5e\u8a9e\u6703\u81ea\u52d5\u4f7f\u7528\u82f1\u8a9e\u4e4b\u7ffb\u8b6f\u3002 ~s~", "3": "~h~~y~ATTENTION~s~~h~\n~r~The key which has no translate will assign English Translation automatically.~s~", + "5": "~h~~y~ATTENTION~s~~h~\n~r~W\u00f6rter die noch nicht von unserem \u00dcbersetzungs-Team \u00fcbersetzt worden sind, werden automatisch durch die englischen W\u00f6rter ersetzt.~s~", "6": "Lingua personalizzata Menu ", "8": "~h~~y~UWAGA~s~~h~\n~r~Wyrazy bez gotowego t\u0142umaczenia bed\u0105 automatycznie u\u017cywa\u0107 s\u0142\u00f3w angielskich.~s~", + "9": "~h~~y~ATEN\u00c7\u00c3O~s~~h~\n~r~As palavras que n\u00e3o foram traduzidas ser\u00e3o automaticamente mudadas para o Ingl\u00eas.~s~", "10": "~h~~y~\u0412\u041d\u0418\u041c\u0410\u041d\u0418\u0415~s~~h~\n~r~ \u041a\u043b\u0430\u0432\u0438\u0448\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439.~s~", "11": "~h~~y~ ATENCI\u00d3N ~s~~h~\n~r~Palabras que no tienen traducci\u00f3n, usar\u00e1n la traducci\u00f3n al ingles~s~", "13": "~h~~y~D\u0130KKAT~s~~h~\n~r~\u00c7evirilmeyen sat\u0131rlar otomatik olarak \u0130ngilizce ayarlan\u0131r.~s~", @@ -1814,129 +2985,161 @@ "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092\u76f4\u7dda\u306b\u8a2d\u7f6e\u3057\u307e\u3059\u3002", "2": "\u8acb\u5c07 ~o~ \u4e09\u89d2\u9310 ~s~ \u5448\u76f4\u7dab\u653e\u7f6e\u3002", "3": "Place the ~o~pylons~s~ in a straight line.", + "5": "Platziere die ~o~Pylonen~s~ in einer geraden Linie", "6": "Posiziona coni in linea retta.", "8": "Postaw ~o~pacho\u0142ki~s~ w prostej linii", + "9": "Coloque os ~o~cones~s~ em uma linha reta.", "10": "\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435 ~o~\u043a\u043e\u043d\u0443\u0441\u043e\u0432~s~ \u043f\u043e \u043f\u0440\u044f\u043c\u043e\u0439 \u043b\u0438\u043d\u0438\u0438.", "11": "Poner los ~o~pilones~s~ en l\u00ednea recta.", "13": "~o~Dubalar\u0131~s~ s\u0131ras\u0131n\u0131 d\u00fcz olarak ayarla.", "14": "Umistete ~o~dopravni kuzele~s~ do prime linie.", + "16": "Placera ~o~konerna~s~ p\u00e5 rad.", "20": "Sud\u0117lioti ~o~k\u016bgius~s~ tiesia juosta" }, "PylonFreezeItemDesc": { "0": "\u6709\u52b9\u3060\u3068~o~\u30d1\u30a4\u30ed\u30f3~s~\u304c\u8a2d\u7f6e\u3055\u308c\u305f\u5834\u6240\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059\u3002\n\u56fa\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u5834\u5408\u3001\u5f53\u305f\u308b\u3068\u52d5\u3044\u305f\u308a\u3001\u5012\u308c\u307e\u3059\u3002", "2": "\u5553\u52d5\u6642\uff0c ~o~ \u4e09\u89d2\u9310 ~s~ \u5c07\u6703\u88ab\u56fa\u5b9a\uff0c\u7121\u6cd5\u88ab\u649e\u64ca\n\u5982\u672a\u5553\u52d5\uff0c\u4e09\u89d2\u9310\u906d\u5230\u649e\u64ca\u6642\u5c07\u6703\u88ab\u649e\u5012\u3002", "3": "When enabled, the ~o~pylon ~s~ will be anchored to where it was placed.\nIf it's not enabled, it will move or fall when hit.", + "5": "Wenn diese Funktion aktiviert ist, wird der ~o~Pylon ~s~verankert.\nFalls diese Funktion ~o~nicht~s~ aktiviert ist, wird der Pylon umfallen. ", "6": "Quando abilitato, il cono sar\u00e0 ancorato al punto in cui \u00e8 stato posizionato.\n Se non \u00e8 abilitato, si muover\u00e0 o cadr\u00e0 quando viene colpito.", "8": "Po w\u0142\u0105czeniu, ~o~pacho\u0142ek ~s~ b\u0119dzie zakotwiczony w miejscu, w kt\u00f3rym zosta\u0142 umieszczony.\nJe\u015bli ta opcja nie jest w\u0142\u0105czona, b\u0119dzie si\u0119 porusza\u0142 lub spadnie kiedy uderzony.", + "9": "Quando habilitados, os ~o~cones ~s~ ficar\u00e3o grudados nos lugares em que foram postos.\nQuando n\u00e3o est\u00e1 habilitado, os cones se mover\u00e3o e cair\u00e3o quando atingidos.", "10": "\u041a\u043e\u0433\u0434\u0430 \u044d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432\u043a\u043b\u044e\u0447\u0435\u043d, ~o~\u043a\u043e\u043d\u0443\u0441 ~s~ \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d \u043d\u0430 \u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0433\u0434\u0435 \u043e\u043d \u0431\u044b\u043b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d.\n\u0415\u0441\u043b\u0438 \u043e\u043d \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d, \u0442\u043e \u043f\u0440\u0438 \u0443\u0434\u0430\u0440\u0435 \u043e\u043d \u0441\u0434\u0432\u0438\u043d\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0443\u043f\u0430\u0434\u0435\u0442.", "11": "Cuando est\u00e1 habilitado, ~o~pilones~s~ se anclar\u00e1 a la ubicaci\u00f3n donde se coloc\u00f3.\nSi no est\u00e1 habilitado, se mover\u00e1 o caer\u00e1 cuando sea golpeado.", "13": "Bu \u00f6zelli\u011fi aktifle\u015ftirirseniz, ~o~dubalar~s~ devrilmez.\nE\u011fer devre d\u0131\u015f\u0131 b\u0131rak\u0131rsan\u0131z, \u00e7arpt\u0131\u011f\u0131n\u0131zda devrilir.", "14": "Pokud tohle neni, ~o~povoleno ~s~ tak NPC mohou je schodit ci prejet.", + "16": "N\u00e4r denna \u00e4r aktiverad, kommer ~o~konen ~s~ bli fast satt d\u00e4r den placeras.\nOm denna inte \u00e4r aktiverad kommer konen kunna ramla och flyttas.", "20": "Kai \u012fjungta, ~o~k\u016bgiai~s~ sustings savo vietoje..\nJeigu jie n\u0117ra sustingdinti, jie gal\u0117s laisvai pervirsti, nukristi." }, "PylonTypeItemDesc": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u7a2e\u985e\u3092\u9078\u629e\u3057\u307e\u3059\u3002", "2": "\u8a2d\u5b9a ~o~ \u4e09\u89d2\u9310 ~s~ \u7684\u6a21\u578b", "3": "Select the ~o~pylons~s~ model.", + "5": "W\u00e4hle das Modell der Pylonen aus.", "6": "Seleziona il modello cono stradale.", "8": "Wybierz model ~o~pacho\u0142k\u00f3w~s~ ", + "9": "Escolha o modelo dos ~o~cones~s~", "10": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0442\u0438\u043f\u0430 \u043a\u043e\u043d\u0443\u0441\u043e\u0432", "11": "Seleccionar modelo de ~o~pilones~s~ ", "13": "~o~Dubalar\u0131n~s~ modelini se\u00e7in.", "14": "Vyberte model ~o~dopravnich kuzelu~s~.", + "16": "V\u00e4lj ~o~konens~s~ modell.", "20": "Pasirinkti ~o~k\u016bgi\u0173~s~ i\u0161vaizd\u0105" }, "SetPylonPosesDesc": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u8a2d\u7f6e\u4f4d\u7f6e\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\n\u30bf\u30d6\u306e\u80cc\u666f\u3067\u72b6\u614b\u3092\u793a\u3057\u3066\u3044\u307e\u3059\u3002\n~y~\u9ec4\u8272~s~: \u672a\u6307\u5b9a\n~g~\u7dd1\u8272~s~: \u6307\u5b9a\u6e08\u307f\n~r~\u8d64\u8272~s~: \u6307\u5b9a\u4e2d", "2": "\u6307\u5b9a ~o~ \u4e09\u89d2\u9310 ~s~ \u7684\u4f4d\u7f6e\u3002\n\u9078\u9805\u5361\u7684\u80cc\u666f\u6307\u793a\u72c0\u614b\u3002\uff08\u6b64\u53e5\u7ffb\u8b6f\u5c07\u6703\u65bc\u4e0b\u6b21\u66f4\u65b0\u6642\u4e88\u4ee5\u4fee\u6b63\uff09\n~y~ \u9ec3\u8272 ~s~: \u7121\n~g~ \u7da0\u8272 ~s~: \u88ab\u9078\u64c7\n~r~ \u7d05\u8272 ~s~: \u9078\u64c7\u4e2d", "3": "Specifies the place positions of the ~o~pylons~s~.\nThe background of the tab indicates the state.\n~y~Yellow ~s~: None\n~g~Green ~s~: Specified\n~r~Red ~s~: Specifying now", + "5": "W\u00e4hlt die Position der ~o~Pylonen~s~ aus.\nDie Hintergrundanzeige zeigt den Zustand.\n~y~Yellow ~s~: Keine\n~g~Green ~s~: Ausgew\u00e4hlt\n~r~Red ~s~: Wird ausgew\u00e4hlt", "6": "Specifica la posizione dei coni stradale.\n Lo sfondo della scheda indica lo stato.\n ~y~Giallo ~s~: nessuno\n ~g~Verde ~s~: specificato\n ~r~Rosso ~s~: Specificato ora", "8": "Podaje pozycj\u0119 ~o~pacho\u0142k\u00f3w~s~.\nKolor zak\u0142adki oznacza stan:\n~y~\u017b\u00f3\u0142ty ~s~: \u017baden\n~g~Zielony ~s~: Okre\u015blony\n~r~Czerwony ~s~: Okre\u015blany", + "9": "Especifica a posi\u00e7\u00e3o dos ~o~cones~s~.\nA cor fundo indica o estado.\n~y~Amarelo ~s~: Nenhum\n~g~Verde ~s~: Especificado\n~r~Vermelho ~s~: Especificando agora", "10": "\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 ~o~\u043a\u043e\u043d\u0443\u0441\u043e\u0432~s~.\n\u0424\u043e\u043d \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.\n~y~ \u0416\u0435\u043b\u0442\u044b\u0439 ~s~: \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442\n~g~\u0417\u0435\u043b\u0435\u043d\u044b\u0439 ~s~: \u0423\u043a\u0430\u0437\u0430\u043d\u043e\n~r~\u041a\u0440\u0430\u0441\u043d\u044b\u0439 ~s~: \u0423\u0442\u043e\u0447\u043d\u044f\u0435\u043c \u0441\u0435\u0439\u0447\u0430\u0441", "11": "Especifica las posiciones del lugar de los ~o~pilones~s~.\nColor indica estado de los pilones.\n~y~Amarillo~s~: Ninguno\n~g~Verde~s~: Especificado\n~r~Rojo~s~: Especificando ahora", "13": "~o~Dubalar\u0131n~s~ konumunu belirler.\nDurumun arka plandaki i\u015flemlerini g\u00f6sterir.\n~y~Sar\u0131 ~s~: Bo\u015f\n~g~Ye\u015fil ~s~: Belirtilmi\u015f\n~r~K\u0131rm\u0131z\u0131 ~s~: Belirleniyor", "14": "Urcuje umisteni ~o~dopravnich kuzelu~s~.\nPozadi menu oznacuje stav.\n~y~Zluta ~s~: Zadny\n~g~Zelena ~s~: Urceno\n~r~Cervena ~s~: Specifikuje se nyni", + "16": "Anger platspositionerna f\u00f6r ~o~konerna~s~.\nBakgrundsf\u00e4rgen indikerar tillst\u00e5ndet.\n~y~Gul ~s~: Inga\n~g~Gr\u00f6n ~s~: Specificerad\n~r~R\u00f6d ~s~: Specificerar nu", "20": "Nustato ~o~k\u016bgi\u0173~s~ d\u0117liojimo viet\u0105\nFonas nurodo nustatymo status\u0105.\n~y~Geltona~s~: Joksai\n~g~\u017dalia~s~: Nustatyta\n~r~Raudona~s~: Nustatoma" }, "PylonCountItemDesc": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u8a2d\u7f6e\u672c\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\n\u73fe\u5728\u306e\u672c\u6570: {0}", "2": "\u4e00\u7d44 ~o~ \u4e09\u89d2\u9310 ~s~ \u7684\u6578\u91cf\n\u76ee\u524d\u6578\u91cf: {0}", "3": "Set for ~o~pylons~s~ count.\nNow count: {0}", + "5": "Gibt die aktuelle Anzahl von platzierten Pylonen an.\nAnzahl an Pylonen: {0}", "6": "Impostato per il conteggio di cono stradale\n Ora conta: {0}", "8": "Ilo\u015b\u0107 ~o~pacho\u0142k\u00f3w~s~\nObecna ilo\u015b\u0107: {0}", + "9": "Defina a quantidade de ~o~cones~s~.\nQuantidade atual: {0}", "10": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f ~o~ \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u043d\u0443\u0441\u043e\u0432~s~.\n\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0439\u0442\u0435: {0}", "11": "Cantidad de los ~o~pilones~s~.\nCantidad ahora: {0}", "13": "~o~Dubalar~s~ i\u00e7in adet belirleyin.\n\u015euanki adet: {0}", "14": "Nastavte na pocet ~o~dopravnich kuzelu~s~.\nNyni pocitejte: {0}", + "16": "Anger antalet ~o~koner ~s~ som ska s\u00e4ttas ut.\nNuvarande antal: {0}", "20": "Nustatyti ~o~k\u016bgi\u0173~s~ kiek\u012f\nDabartinis: {0}" }, "PlacePylonsItemDesc": { "0": "\u8a2d\u5b9a\u306b\u57fa\u3065\u3044\u3066~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092\u8a2d\u7f6e\u3057\u307e\u3059\u3002", "2": "\u4f9d\u64da\u8a2d\u5b9a\u653e\u7f6e ~o~\u4e09\u89d2\u9310 ~s~ \u3002", "3": "Places ~o~pylons ~s~ based on settings.", + "5": "Setze den ~o~Plyon ~s~basierend auf deinen Einstellungen auf den Boden.", "6": "Posiziona cono stradale in base alle impostazioni.", "8": "Ustawia ~o~pacho\u0142ki~s~ na podstawie ustawie\u0144", + "9": "Posiciona os ~o~cones ~s~ baseados nas configura\u00e7\u00f5es.", "10": "\u0420\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 ~o~\u043a\u043e\u043d\u0443\u0441\u044b~s~ \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.", "11": "Coloque ~o~pilones~s~ seg\u00fan la configuraci\u00f3n", "13": "~o~Dubalar\u0131~s~ ayarland\u0131\u011f\u0131 gibi yerle\u015ftir.", "14": "Umisti ~az~dopravni kuzely ~s~ na zaklade nastaveni.", + "16": "Placerar ut ~o~koner ~s~ baserad p\u00e5 inst\u00e4llningar.", "20": "Sudelioti ~o~k\u016bgius~s~ pagal nustatymus" }, "ResetPylonItemDesc": { "0": "~o~\u30d1\u30a4\u30ed\u30f3~s~\u306e\u8a2d\u5b9a\u3092~r~\u30ea\u30bb\u30c3\u30c8~s~\u3057\u307e\u3059\u3002\n(\u65e2\u5b58\u306e\u30d1\u30a4\u30ed\u30f3\u306f~y~\u524a\u9664\u3055\u308c\u307e\u305b\u3093~s~\u3002)", "2": "~r~ \u91cd\u7f6e ~s~ ~o~ \u4e09\u89d2\u9310 ~s~ \u7684\u8a2d\u5b9a\u3002\n( ~y~ \u4e0d\u6703\u53d6\u6d88 ~s~ \u591a\u51fa\u4e4b\u4e09\u89d2\u9310)\u3002", "3": "~r~Reset~s~ ~o~pylon~s~ settings.\n(~y~No delete~s~ existing pylons.)", + "5": "Setzt die Pylonen-Einstellungen zur\u00fcck.\n Bestehende Pylonen werden bei diesem Prozess ~y~nicht~s~ gel\u00f6scht.", "6": "Ripristina le impostazioni del cono.\n Nessuna eliminazione dei coni esistenti.", "8": "~r~Resetuj~s~ ustawienia ~o~pacho\u0142k\u00f3w~s~\n(~y~Nie usuwa~s~ istniej\u0105cych pacho\u0142k\u00f3w.)", + "9": "~r~Redefine~s~ as configura\u00e7\u00f5es do ~o~cone~s~\n(~y~N\u00e3o apaga~s~ cones que j\u00e1 existem.)", "10": "~r ~\u0421\u0431\u0440\u043e\u0441\u044c\u0442\u0435~s ~ ~o~\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0443\u0441\u043e\u0432 ~s~.\n(~y~\u041d\u0435 \u0443\u0434\u0430\u043b\u044f\u0442\u044c~s~ \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043d\u0443\u0441\u043d\u044b\u0435 \u0437\u043d\u0430\u043a\u0438.)", "11": "~r~Reiniciar~s~ ajustes de los ~o~pilones~s~.\n(~y~Esto no elimina~s~ los pilones existentes.)", "13": "~o~Dubalar\u0131n~s~ ayarlar\u0131n\u0131 ~r~s\u0131f\u0131rlar~s~.\n(Mevcut dubalar\u0131 ~y~silmez~s~.)", "14": "~r~Odstranis~s~ ~o~prave pokladane~s~ dopravni kuzele.\n(~y~Zadne odstraneni~s~ existujicich dopravnich kuzelu.)", + "16": "~r~\u00c5terst\u00e4ll~s~ ~o~kon~s~ inst\u00e4llningar.\n(Befintliga koner ~y~raderas ej~s~.)", "20": "~r~Perrinkti~s~ ~o~k\u016bgi\u0173~s~ nustatymus\n(~y~Nei\u0161trina~s~ esan\u010di\u0173 k\u016bgi\u0173)" }, "PlacePylonItemDesc": { "0": "\u904b\u3093\u3067\u3044\u308b~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092~y~\u76ee\u306e\u524d~s~\u306b~b~\u8a2d\u7f6e~s~\u3057\u307e\u3059\u3002", "2": "\u65bc ~y~ \u73a9\u5bb6\u524d\u65b9 ~s~ \u653e\u7f6e ~o~ \u4e09\u89d2\u9310 ~s~ \u3002", "3": "~b~Place~s~ the ~o~pylon~s~ which is carrying in ~y~front of the player~s~.", + "5": "~b~Platziere~s~ den ~o~Pylon~s~ ~y~vor dem Spieler~s~.", "6": "Posiziona cono stradale che sta portando davanti al giocatore. ", "8": "~b~Postaw~s~ ~o~pacho\u0142ek~s~, kt\u00f3ry aktualnie niesiesz ~y~przed sob\u0105~s~.", + "9": "~b~Coloque~s~ o ~o~cone~s~ que est\u00e1 sendo carregado ~y~na frente do jogador~s~.", "10": "~b~ \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c ~s~ \u0434\u043e\u0440\u043e\u0436\u043d\u044b\u0439 ~o~ \u043a\u043e\u043d\u0443\u0441 ~s~, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434 \u0438\u0433\u0440\u043e\u043a\u043e\u043c ~s~.", "11": "~b~Coloca~s~ el ~o~pil\u00f3n~s~ que llevas, ~y~delante de ti~s~.", "13": "~b~Elinizdeki~s~ ~o~dubalar\u0131~s~ ~y~yere~s~ b\u0131rak\u0131n.", "14": "~b~Umisti~~kuzel~s~, ktery nesete ~pred hracem~.", + "16": "~b~S\u00e4tt ner~s~ ~o~konen~s~ ~y~du b\u00e4r~s~.", "20": "~b~Pad\u0117ti~s~ ~o~k\u016bg\u012f~s~ kuris ne\u0161amas ~y~i\u0161 priekio~s~" }, "CarryPylonItemDesc": { "0": "\u4e00\u756a\u8fd1\u304f\u306e~b~\u30d1\u30a4\u30ed\u30f3~s~\u3092~b~\u904b\u3073\u307e\u3059~s~\u3002", "2": "~b~ \u63d0\u8d77 ~s~ \u6700\u8fd1\u4e4b ~o~ \u4e09\u89d2\u9310 ~s~ \u3002", "3": "~b~Carry~s~ the nearest ~o~pylon~s~.", + "5": "~b~Hebe~s~ den n\u00e4chsten ~o~Pylonen~s~ auf.", "6": "Trasporta i coni", "8": "~b~Podnie\u015b~s~ najbli\u017cszy ~o~pacho\u0142ek~s~.", + "9": "~b~Carregue o~s~ ~o~cone~s~ mais pr\u00f3ximo.", "10": "~b~\u0423\u0431\u0440\u0430\u0442\u044c ~s~ \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439~o~\u043a\u043e\u043d\u0443\u0441~s~.", "11": "~b~Recojar~s~ ~o~pil\u00f3n~s~ m\u00e1s cercano.", "13": "~b~En yak\u0131n~s~ ~o~dubay\u0131~s~ ta\u015f\u0131.", "14": "~b~Neste~ nejblizsi ~o~kuzel~s~.", + "16": "~b~Plocka upp~s~ n\u00e4rmaste ~o~kon~s~.", "20": "~b~Ne\u0161tis~s~ artimiausi\u0105 ~o~k\u016bg\u012f~s~" }, "DeletePylonItemDesc": { "0": "\u8a2d\u5b9a\u306b\u57fa\u3065\u3044\u3066~o~\u30d1\u30a4\u30ed\u30f3~s~\u3092~r~\u524a\u9664~s~\u3057\u307e\u3059\u3002", "2": "\u6839\u64da\u8a2d\u5b9a~r~ \u522a\u9664 ~s~ \u73fe\u6709\u4e4b ~o~\u4e09\u89d2\u9310 ~s~\u3002", "3": "Delete ~o~pylons ~s~ based on settings.", + "5": "L\u00f6sche ~o~Pylonen ~s~ basierend auf deinen Einstellungen.", "6": "Elimina cono stradale in base alle impostazioni.", "8": "Usu\u0144 ~o~Pacho\u0142ki~s bazowane na ustawieniach.", + "9": "Apague os~o~cones ~s~ baseados nas configura\u00e7\u00f5es.", "10": "Delete ~o~pylons ~s~ based on settings.", "11": "Elimina ~o~pilones~s~ seg\u00fan la configuraci\u00f3n", "13": "~o~Dubalar\u0131~s~ ayarland\u0131\u011f\u0131 gibi sil.", "14": "Odstrante ~o~dopravni kuzele ~s~ na zaklade nastaveni.", + "16": "Ta bort ~o~trafik-konen ~s~ baserat p\u00e5 inst\u00e4llningar.", "20": "I\u0161trinti ~o~k\u016bgius~s~ pagal nustatymus" }, "TranslateStatus": { "0": "\u7ffb\u8a33\u7387: {0}%", "2": "\u7ffb\u8b6f\u5b8c\u6210\u7387: {0} %", "3": "Translate Status: {0}%", + "4": "Statut de la traduction", "5": "\u00dcbersetzungsstatus: {0}%", "6": "Stato traduzione: {0}%", "8": "Status uko\u0144czenia t\u0142umaczenia: {0}%", + "9": "Estado da Tradu\u00e7\u00e3o: {0}%", "10": "\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430: {0}%", "11": "Traducir estado: {0}%", "13": "\u00c7eviri Durumu {0}%", diff --git a/DynamicLSPDFR/Settings/ClientSettings.cs b/DynamicLSPDFR/Settings/ClientSettings.cs index 80edfce..5e07cdf 100644 --- a/DynamicLSPDFR/Settings/ClientSettings.cs +++ b/DynamicLSPDFR/Settings/ClientSettings.cs @@ -2,6 +2,18 @@ namespace DynamicLSPDFR.Settings; internal static class ClientSettings { + internal static bool DangerousFoundIsEnabled = true; + internal static bool GangShootoutIsEnabled = true; + internal static bool HitAndRunIsEnabled = true; + internal static bool SushiIsEnabled = true; + internal static bool BankRobberyIsEnabled = true; + internal static bool StoreRobberyIsEnabled = true; + internal static bool StreetFightIsEnabled = true; + internal static bool CriminalFoundIsEnabled = true; + internal static bool DynamicPursuitIsEnabled = true; + internal static bool StolenCarPursuitIsEnabled = true; + internal static bool StolenMoneyTruckIsEnabled = true; + private const string FilePath = "plugins/LSPDFR/DynamicLSPDFR.ini"; internal static InitializationFile LoadFile(string path) @@ -27,6 +39,10 @@ internal static void LoadSettings() { Main.OpenContextMenuKey = SettingFile.ReadString("Keys", "OpenContextMenuKey", "O").ConvertToKey(); Main.OpenContextMenuModifierKey = SettingFile.ReadString("Keys", "OpenContextMenuKey-Modifier", "None").ConvertToKey(); + // Main.OpenTrafficTicketsMenuKey = SettingFile.ReadString("Keys", "OpenTrafficTicketsMenuKey", "U").ConvertToKey(); + // Main.OpenTrafficTicketsMenuModifierKey = SettingFile.ReadString("Keys", "OpenTrafficTicketsMenuKey-Modifier", "LControlKey").ConvertToKey(); + Main.UnitsTeleportToNearbyPlayerKey = SettingFile.ReadString("Keys", "UnitsTeleportToNearbyPlayerKey", "U").ConvertToKey(); + Main.UnitsTeleportToNearbyPlayerModifierKey = SettingFile.ReadString("Keys", "UnitsTeleportToNearbyPlayerKey-Modifier", "LControlKey").ConvertToKey(); Main.Language = SettingFile.ReadEnum("General", "Language", 0); Main.Random = SettingFile.ReadEnum("General", "RandomNumberAlgorithm", 0); @@ -34,6 +50,25 @@ internal static void LoadSettings() Main.OfficerName = SettingFile.ReadString("CalloutOptions", "OfficerName", "Officer"); Main.StationName = SettingFile.ReadString("CalloutOptions", "StationName", ""); + Main.CoronerSpawnDistance = (float)SettingFile.ReadDouble("UnitsSetting", "CoronerSpawnDistance", 120f); + + // Callout Enable + DangerousFoundIsEnabled = SettingFile.ReadBoolean("Callouts", "FoundDangerousPerson", true); + GangShootoutIsEnabled = SettingFile.ReadBoolean("Callouts", "GangShootout", true); + HitAndRunIsEnabled = SettingFile.ReadBoolean("Callouts", "HitAndRun", true); + SushiIsEnabled = SettingFile.ReadBoolean("Callouts", "SushiTerrorism", true); + BankRobberyIsEnabled = SettingFile.ReadBoolean("Callouts", "BankRobbery", true); + StoreRobberyIsEnabled = SettingFile.ReadBoolean("Callouts", "StoreRobbery", true); + StreetFightIsEnabled = SettingFile.ReadBoolean("Callouts", "StreetFight", true); + CriminalFoundIsEnabled = SettingFile.ReadBoolean("Callouts", "WantedCriminalFound", true); + DynamicPursuitIsEnabled = SettingFile.ReadBoolean("Callouts", "DynamicPursuit", true); + StolenCarPursuitIsEnabled = SettingFile.ReadBoolean("Callouts", "StolenCarPursuit", true); + StolenMoneyTruckIsEnabled = SettingFile.ReadBoolean("Callouts", "StolenMoneyTruck", true); + + // TrafficTickets.LimitOfSeize = SettingFile.ReadInt32("TrafficTickets", "LimitOfSeize", 10); + // TrafficTickets.Unit = SettingFile.ReadString("TrafficTickets", "Unit", "$"); + // TrafficTickets.RightUnitPosition = SettingFile.ReadBoolean("TrafficTickets", "RightUnitPosition", false); + // foreach (var c in CalloutList.AllCallouts) // { // CalloutsEnable.Add(SettingFile.ReadBoolean("Callouts", c.Item2, true)); diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_01.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_01.wav new file mode 100644 index 0000000..a9461d0 Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_01.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_02.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_02.wav new file mode 100644 index 0000000..1ef919a Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_02.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_03.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_03.wav new file mode 100644 index 0000000..011732e Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_03.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_04.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_04.wav new file mode 100644 index 0000000..8f608c6 Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_04.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_05.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_05.wav new file mode 100644 index 0000000..25ecbcb Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_BANK_ROBBERY_05.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_01.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_01.wav new file mode 100644 index 0000000..65d38d0 Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_01.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_02.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_02.wav new file mode 100644 index 0000000..899816c Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_02.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_03.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_03.wav new file mode 100644 index 0000000..63745d0 Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_03.wav differ diff --git a/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_04.wav b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_04.wav new file mode 100644 index 0000000..2a0acd2 Binary files /dev/null and b/DynamicLSPDFR/Sounds/DynamicLSPDFR/DL_CRIME_HIT_AND_RUN_04.wav differ diff --git a/DynamicLSPDFR/Units/Coroner/Coroner.cs b/DynamicLSPDFR/Units/Coroner/Coroner.cs new file mode 100644 index 0000000..59ac822 --- /dev/null +++ b/DynamicLSPDFR/Units/Coroner/Coroner.cs @@ -0,0 +1,498 @@ +namespace DynamicLSPDFR.Units; + +internal class Coroner +{ + private static Model vehicleModel = new("SPEEDO"); + private static Model pedModel = new("S_M_M_Doctor_01"); + private static List bodiesBeingHandled = new(); + + private List deadBodies = new(); + private Vehicle vehicle; + private Ped driver, passenger; + private Vector3 destination; + private List bodyBags = new(); + private Blip blip; + + internal static bool CanBeCalled(Vector3 destination) => GetNearbyDeadPeds(destination).Count != 0; + internal static bool CanBeCalled() => CanBeCalled(Game.LocalPlayer.Character.Position); + + internal static void CoronerMain() + { + if (GetNearbyDeadPeds(Game.LocalPlayer.Character.Position).Count == 0) + { + MessageExtensions.SendMessageInGame(Translation.GetString("NoDeadBodies")); + return; + } + new Coroner(Game.LocalPlayer.Character.Position).HandleCoroner(); + } + + public Coroner(Vector3 destination) + { + this.destination = destination; + this.deadBodies = GetNearbyDeadPeds(destination); + } + + private void HandleCoroner() + { + GameFiber.StartNew(delegate + { + try + { + Game.DisplayNotification(string.Format(Translation.GetString("UnitRequested"), Translation.GetString("Coroner"))); + Functions.PlayScannerAudioUsingPosition("ASSISTANCE_REQUIRED IN_OR_ON_POSITION", Game.LocalPlayer.Character.Position); + Functions.PlayPlayerRadioAction(EPoliceRadioAction.Shoulder, 5000); + // Game.LocalPlayer.Character.Tasks.PlayAnimation("random@arrests", "generic_radio_chatter", 1.5f, AnimationFlags.UpperBodyOnly | AnimationFlags.SecondaryTask); + GameFiber.Wait(3000); + + float Heading; + bool UseSpecialID = true; + Vector3 SpawnPoint; + float travelDistance; + int waitCount = 0; + while (true) + { + GetSpawnPoint(destination, out SpawnPoint, out Heading, UseSpecialID); + travelDistance = NativeFunction.Natives.CALCULATE_TRAVEL_DISTANCE_BETWEEN_POINTS(SpawnPoint.X, SpawnPoint.Y, SpawnPoint.Z, destination.X, destination.Y, destination.Z); + waitCount++; + if (Vector3.Distance(destination, SpawnPoint) > Main.CoronerSpawnDistance - 15f) + { + if (travelDistance < (Main.CoronerSpawnDistance * 4.5f)) + { + Vector3 directionFromVehicleToPed1 = (destination - SpawnPoint); + directionFromVehicleToPed1.Normalize(); + if (Math.Abs(MathHelper.NormalizeHeading(Heading) - MathHelper.NormalizeHeading(MathHelper.ConvertDirectionToHeading(directionFromVehicleToPed1))) < 150f) break; + } + } + if (waitCount >= 400) UseSpecialID = false; + else if (waitCount == 600) ShowTeleportHelp(); + else if (waitCount >= 600 && KeyExtensions.IsKeysDown(Keys.Y)) + { + SpawnPoint = destination.Around(18f); + break; + } + GameFiber.Yield(); + } + vehicle = new(vehicleModel, SpawnPoint, Heading); + if (vehicle && vehicle.IsValid()) + { + vehicle.IsPersistent = true; + if (vehicle.HasSiren) vehicle.IsSirenOn = true; + blip = vehicle.AttachBlip(); + if (blip && blip.IsValid()) blip.Color = Color.Green; + } + + driver = new(pedModel, Vector3.Zero, 0); + if (driver && driver.IsValid()) + { + driver.IsPersistent = true; + driver.IsRagdoll = false; + driver.BlockPermanentEvents = true; + driver.IsInvincible = true; + driver.WarpIntoVehicle(vehicle, -1); + } + passenger = new(pedModel, Vector3.Zero, 0); + if (passenger && passenger.IsValid()) + { + passenger.IsPersistent = true; + passenger.IsRagdoll = false; + passenger.BlockPermanentEvents = true; + passenger.IsInvincible = true; + passenger.WarpIntoVehicle(vehicle, 0); + } + + DriveToPosition(driver, vehicle, destination); + if (vehicle.HasSiren && vehicle.IsSirenOn) vehicle.IsSirenOn = false; + blip.Delete(); + Game.DisplaySubtitle(new StringBuilder("~b~").Append(Translation.GetString("Coroner")).Append("~s~: ").Append(Translation.GetString($"CoronerComment{RandomNumber.Instance.Next(7)}")).ToString(), 5000); + while (deadBodies.Count > 0) + { + deadBodies.OrderBy(x => x.DistanceTo(driver.Position)); + foreach (Ped body in deadBodies.ToArray()) + { + if (body.Exists() && !bodiesBeingHandled.Contains(body)) DealWithBody(body); + else deadBodies.Remove(body); + } + deadBodies.AddRange(GetNearbyDeadPeds(driver.Position)); + } + LeaveScene(); + } + catch (Exception e) + { + Game.LogTrivial(e.ToString()); + if (driver.Exists()) driver.Delete(); + if (passenger.Exists()) passenger.Delete(); + if (vehicle.Exists()) vehicle.Delete(); + foreach (Entity ent in deadBodies) if (ent.Exists()) ent.Delete(); + deadBodies.Clear(); + foreach (Entity ent in bodyBags) if (ent.Exists()) ent.Delete(); + } + }); + } + + private void DealWithBody(Ped body) + { + bodiesBeingHandled.Add(body); + + if (passenger.IsInAnyVehicle(true)) passenger.Tasks.LeaveVehicle(LeaveVehicleFlags.None); ; + if (driver.IsInAnyVehicle(true)) driver.Tasks.LeaveVehicle(LeaveVehicleFlags.None).WaitForCompletion(); + passenger.Tasks.GoToOffsetFromEntity(body, 10000, -2.0f, -1.0f, 8.0f); + driver.Tasks.GoToOffsetFromEntity(body, 10000, 2.4f, 1.0f, 8.0f).WaitForCompletion(); + + GameFiber.StartNew(() => + { + passenger.Tasks.PlayAnimation("amb@medic@standing@tendtodead@enter", "enter", 8.0F, AnimationFlags.None); + GameFiber.Wait(1000); + passenger.Tasks.PlayAnimation("amb@medic@standing@tendtodead@base", "base", 8.0F, AnimationFlags.Loop).WaitForCompletion(); + }); + + if (Vector3.Distance(driver.Position, Game.LocalPlayer.Character.Position) < 60f) + { + var camera = new Object("prop_pap_camera_01", Vector3.Zero); + driver.Tasks.PlayAnimation("amb@world_human_paparazzi@male@base", "base", 8.0f, AnimationFlags.Loop); + camera.AttachTo(driver, driver.GetBoneIndex(PedBoneId.LeftHand), new(0.0100f, -0.1200f, 0.1200f), new(162.0000f, -176.0000f, -59.7200f)); + + Vector3 dirVector = body.Position - driver.Position; + Vector3 offsetPos = driver.GetOffsetPosition(Vector3.RelativeFront * 1.4f + Vector3.RelativeBottom * 1.5f); + dirVector.Normalize(); + + // Game.DisplaySubtitle(new StringBuilder("~b~").Append(Translation.GetString("Coroner")).Append("~s~: ").Append(CauseOfDeathSpeech(false, body)).ToString(), 6000); + GameFiber.Wait(900); + NativeFunction.Natives.DRAW_SPOT_LIGHT(driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).X, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Y, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Z, dirVector.X, dirVector.Y, dirVector.Z, 100, 100, 100, 90.0f, 50.0f, 90.0f, 80.0f, 90.0f); + GameFiber.Wait(1500); + NativeFunction.Natives.DRAW_SPOT_LIGHT(driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).X, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Y, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Z, dirVector.X, dirVector.Y, dirVector.Z, 100, 100, 100, 90.0f, 50.0f, 90.0f, 80.0f, 90.0f); + GameFiber.Wait(1500); + NativeFunction.Natives.DRAW_SPOT_LIGHT(driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).X, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Y, driver.GetOffsetPosition(Vector3.RelativeFront * 0.5f).Z, dirVector.X, dirVector.Y, dirVector.Z, 100, 100, 100, 90.0f, 50.0f, 90.0f, 80.0f, 90.0f); + GameFiber.Wait(500); + driver.Tasks.Clear(); + passenger.Tasks.PlayAnimation("amb@medic@standing@tendtodead@exit", "exit", 8.0F, AnimationFlags.None).WaitForCompletion(); + GameFiber.Wait(500); + camera.Delete(); + } + + if (body.Exists()) + { + var persona = Functions.GetPersonaForPed(body); + CoronerReport.Save((persona.Forename, persona.Surname, persona.Gender, DateTime.Now, DetermineCauseOfDeath(body))); + + if (deadBodies.Contains(body)) deadBodies.Remove(body); + if (bodiesBeingHandled.Contains(body)) bodiesBeingHandled.Remove(body); + if (body.IsInAnyVehicle(true)) body.Tasks.LeaveVehicle(LeaveVehicleFlags.WarpOut).WaitForCompletion(5000); + bodyBags.Add(new("xm_prop_body_bag", new(body.Position.X, body.Position.Y, (float)World.GetGroundZ(body.Position, true, true)))); + if (body.Exists()) body.Delete(); + } + GameFiber.Wait(2500); + } + + // private static string CauseOfDeathSpeech(bool IsAnimal, Ped body) + // { + // switch (IsAnimal) + // { + // case true: return string.Format(Translation.GetString($"CoronerReportComment{RandomNumber.Instance.Next(3)}"), Translation.GetString("Animal"), Translation.GetString(DetermineCauseOfDeath(body))); + // default: case false: return string.Format(Translation.GetString($"CoronerReportComment{RandomNumber.Instance.Next(3)}"), Translation.GetString("Human"), Translation.GetString(DetermineCauseOfDeath(body))); + // } + // } + + private void LeaveScene() + { + GameFiber.Wait(1000); + foreach (Object obj in bodyBags) if (obj.Exists()) obj.Delete(); + GameFiber.Wait(1000); + + GameFiber.StartNew(() => + { + if (driver.Exists() && Vector3.Distance(driver.Position, Game.LocalPlayer.Character.Position) < 60f) + { + Game.DisplaySubtitle(new StringBuilder("~b~").Append(Translation.GetString("Coroner")).Append("~s~: ").Append(Translation.GetString("CoronerCheckPls")).ToString(), 3000); + passenger.Tasks.FollowNavigationMeshToPosition(vehicle.GetOffsetPositionRight(2), vehicle.Heading, 1.7f); + driver.Tasks.FollowNavigationMeshToPosition(vehicle.GetOffsetPositionRight(-2), vehicle.Heading, 1.7f).WaitForCompletion(10000); + Game.DisplaySubtitle(new StringBuilder("~b~").Append(Translation.GetString("Coroner")).Append("~s~: ").Append(Translation.GetString("CoronerBye")).ToString(), 5000); + passenger.Tasks.EnterVehicle(vehicle, 7000, 0); + driver.Tasks.EnterVehicle(vehicle, 7000, -1).WaitForCompletion(); + } + + GameFiber.Yield(); + driver.Tasks.CruiseWithVehicle(vehicle, 15f, VehicleDrivingFlags.DriveAroundVehicles | VehicleDrivingFlags.DriveAroundObjects | VehicleDrivingFlags.AllowMedianCrossing | VehicleDrivingFlags.YieldToCrossingPedestrians); + + GameFiber.Wait(5000); + passenger.Dismiss(); + driver.Dismiss(); + vehicle.Dismiss(); + }); + } + + private static string DetermineCauseOfDeath(Ped body) + { + Model causeModel = NativeFunction.Natives.GET_PED_CAUSE_OF_DEATH(body); + uint cause = causeModel.Hash; + + return (CauseOfDeathHash)cause switch + { + CauseOfDeathHash.ElectricFence => "CODElectricalShock", + CauseOfDeathHash.WaterCannon => "CODDrownding", + CauseOfDeathHash.FlyingOutOfWindscreen => "CODBang", + CauseOfDeathHash.RunOverByCar => "CODRunOverByCar", + CauseOfDeathHash.Fall => "CODFall", + CauseOfDeathHash.Animal => "CODAnimal", + CauseOfDeathHash.AirstrikeRocket => "CODExplosion", + CauseOfDeathHash.Bleeding => "CODBleeding", + CauseOfDeathHash.BarbedWire => "CODBarbedWire", + CauseOfDeathHash.Drownding => "CODDrownding", + CauseOfDeathHash.DrowndingInVehicle => "CODDrownding", + CauseOfDeathHash.Explosion => "CODExplosion", + CauseOfDeathHash.Exhaustion => "CODExhaustion", + CauseOfDeathHash.Fire => "CODBurn", + CauseOfDeathHash.HelicopterCrash => "CODHelicopterCrash", + + // Weapons + CauseOfDeathHash.Dagger => "CODKnife", + CauseOfDeathHash.Bat => "CODBeatenBlunt", + CauseOfDeathHash.Bottle => "CODBeatenSome", + CauseOfDeathHash.Crowbar => "CODBeatenBlunt", + CauseOfDeathHash.Unarmed => "CODBeatenHand", + CauseOfDeathHash.Flashlight => "CODBeatenBlunt", + CauseOfDeathHash.GolfClub => "CODBeatenBlunt", + CauseOfDeathHash.Hammer => "CODBeatenBlunt", + CauseOfDeathHash.Hatchet => "CODBeatenBlunt", + CauseOfDeathHash.Knuckle => "CODBeatenBlunt", + CauseOfDeathHash.Knife => "CODKnife", + CauseOfDeathHash.Machete => "CODKnife", + CauseOfDeathHash.Switchblade => "CODKnife", + CauseOfDeathHash.Nightstick => "CODBeatenSome", + CauseOfDeathHash.Wrench => "CODBeatenBlunt", + CauseOfDeathHash.Battleaxe => "CODBeatenBlunt", + CauseOfDeathHash.PoolCue => "CODBeatenSome", + CauseOfDeathHash.StoneHatchet => "CODBeatenBlunt", + CauseOfDeathHash.Pistol => "CODShotPistol", + CauseOfDeathHash.Pistol_mk2 => "CODShotPistol", + CauseOfDeathHash.CombatPistol => "CODShotPistol", + CauseOfDeathHash.APPistol => "CODShotPistol", + CauseOfDeathHash.StunGun => "CODElectricalShock", + CauseOfDeathHash.Pistol50 => "CODShotPistol", + CauseOfDeathHash.SnsPistol => "CODShotPistol", + CauseOfDeathHash.SnsPistol_mk2 => "CODShotPistol", + CauseOfDeathHash.HeavyPistol => "CODShotPistol", + CauseOfDeathHash.VintagePistol => "CODShotPistol", + CauseOfDeathHash.FlareGun => "CODBurn", + CauseOfDeathHash.MarksmanPistol => "CODShotPistol", + CauseOfDeathHash.Revolver => "CODShotPistol", + CauseOfDeathHash.Revolver_mk2 => "CODShotPistol", + CauseOfDeathHash.Doubleaction => "CODShotPistol", + CauseOfDeathHash.RayPistol => "CODBurn", + CauseOfDeathHash.CeramicPistol => "CODShotPistol", + CauseOfDeathHash.NavyRevolver => "CODShotPistol", + CauseOfDeathHash.MicroSmg => "CODShotHeavyFirearm", + CauseOfDeathHash.Smg => "CODShotHeavyFirearm", + CauseOfDeathHash.Smg_mk2 => "CODShotHeavyFirearm", + CauseOfDeathHash.AssaultSmg => "CODShotHeavyFirearm", + CauseOfDeathHash.CombatPdw => "CODShotHeavyFirearm", + CauseOfDeathHash.MachinePistol => "CODShotHeavyFirearm", + CauseOfDeathHash.MiniSmg => "CODShotHeavyFirearm", + CauseOfDeathHash.RayCarbine => "CODBurn", + CauseOfDeathHash.PumpShotgun => "CODShotShotgun", + CauseOfDeathHash.PumpShotgun_mk2 => "CODShotShotgun", + CauseOfDeathHash.SawnOffShotgun => "CODShotShotgun", + CauseOfDeathHash.AssaultShotgun => "CODShotShotgun", + CauseOfDeathHash.BullpupShotgun => "CODShotShotgun", + CauseOfDeathHash.Musket => "CODShotShotgun", + CauseOfDeathHash.HeavyShotgun => "CODShotShotgun", + CauseOfDeathHash.DbShotgun => "CODShotShotgun", + CauseOfDeathHash.AutoShotgun => "CODShotShotgun", + CauseOfDeathHash.AssaultRifle => "CODShotRifle", + CauseOfDeathHash.AssaultRifle_mk2 => "CODShotRifle", + CauseOfDeathHash.Carbinerifle => "CODShotRifle", + CauseOfDeathHash.Carbinerifle_mk2 => "CODShotRifle", + CauseOfDeathHash.AdvancedRifle => "CODShotRifle", + CauseOfDeathHash.SpecialCarbine => "CODShotRifle", + CauseOfDeathHash.SpecialCarbine_mk2 => "CODShotRifle", + CauseOfDeathHash.BullpupRifle => "CODShotRifle", + CauseOfDeathHash.BullpupRifle_mk2 => "CODShotRifle", + CauseOfDeathHash.CompactRifle => "CODShotRifle", + CauseOfDeathHash.Mg => "CODShotHeavyFirearm", + CauseOfDeathHash.CombatMg => "CODShotHeavyFirearm", + CauseOfDeathHash.CombatMg_mk2 => "CODShotHeavyFirearm", + CauseOfDeathHash.Gusenberg => "CODShotHeavyFirearm", + CauseOfDeathHash.SniperRifle => "CODShotHeavyFirearm", + CauseOfDeathHash.HeavySniper => "CODShotHeavyFirearm", + CauseOfDeathHash.HeavySniper_mk2 => "CODShotHeavyFirearm", + CauseOfDeathHash.MarksmanRifle => "CODShotHeavyFirearm", + CauseOfDeathHash.MarksmanRifle_mk2 => "CODShotHeavyFirearm", + CauseOfDeathHash.Rpg => "CODExplosion", + CauseOfDeathHash.GrenadeLauncher => "CODExplosion", + CauseOfDeathHash.MiniGun => "CODShotHeavyFirearm", + CauseOfDeathHash.Firework => "CODExplosion", + CauseOfDeathHash.RailGun => "CODBurn", + CauseOfDeathHash.HomingLauncher => "CODExplosion", + CauseOfDeathHash.CompactLauncher => "CODExplosion", + CauseOfDeathHash.RayMiniGun => "CODBurn", + CauseOfDeathHash.Grenade => "CODExplosion", + CauseOfDeathHash.BzGas => "CODChoking", + CauseOfDeathHash.SmokeGrenade => "CODChoking", + CauseOfDeathHash.Flare => "CODBurn", + CauseOfDeathHash.Molotov => "CODBurn", + CauseOfDeathHash.StickyBomb => "CODExplosion", + CauseOfDeathHash.ProxMine => "CODExplosion", + CauseOfDeathHash.PipeBomb => "CODExplosion", + CauseOfDeathHash.PetrolCan => "CODDrownding", + CauseOfDeathHash.FireExtinguisher => "CODChoking", + CauseOfDeathHash.HazardCan => "CODDrownding", + _ => "CODUnknown" + }; + } + + private static List GetNearbyDeadPeds(Vector3 pos, float radius = 35) + { + List nearbyDeads = new(); + foreach (Ped ped in World.EnumeratePeds()) + { + if (ped.Exists() && ped.IsDead && !bodiesBeingHandled.Contains(ped) && ped.DistanceTo(pos) < radius) nearbyDeads.Add(ped); + } + return nearbyDeads; + } + + private static void DriveToPosition(Ped driver, Vehicle veh, Vector3 pos) + { + int drivingLoopCount = 0; + bool transportVanTeleported = false; + int waitCount = 0; + bool ForceTeleport = false; + + GameFiber.StartNew(delegate + { + while (!ForceTeleport) + { + GameFiber.Yield(); + if (KeyExtensions.IsKeysDown(Main.UnitsTeleportToNearbyPlayerKey, Main.UnitsTeleportToNearbyPlayerModifierKey)) + { + GameFiber.Sleep(500); + if (KeyExtensions.IsKeysDownRightNow(Main.UnitsTeleportToNearbyPlayerKey, Main.UnitsTeleportToNearbyPlayerModifierKey)) + { + GameFiber.Sleep(500); + if (KeyExtensions.IsKeysDown(Main.UnitsTeleportToNearbyPlayerKey, Main.UnitsTeleportToNearbyPlayerModifierKey)) ForceTeleport = true; + else ShowTeleportHelp(); + } + } + } + }); + Task driveToPed = null; + if (driver && driver.IsValid()) driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraight).WaitForCompletion(500); + if (veh && veh.IsValid()) + { + while (Vector3.Distance(veh.Position, pos) > 35f) + { + veh.Repair(); + if (driveToPed == null || !driveToPed.IsActive) driveToPed = driver.Tasks.DriveToPosition(pos, MathHelper.ConvertKilometersPerHourToMetersPerSecond(60f), VehicleDrivingFlags.DriveAroundVehicles | VehicleDrivingFlags.DriveAroundObjects | VehicleDrivingFlags.AllowMedianCrossing | VehicleDrivingFlags.YieldToCrossingPedestrians); + + NativeFunction.Natives.SET_DRIVE_TASK_DRIVING_STYLE(driver, 786607); + NativeFunction.Natives.SET_DRIVER_AGGRESSIVENESS(driver, 0f); + NativeFunction.Natives.SET_DRIVER_ABILITY(driver, 1f); + GameFiber.Wait(600); + + waitCount++; + if (waitCount == 70) ShowTeleportHelp(); + if (veh.Speed < 2f) drivingLoopCount++; + if (Vector3.Distance(pos, veh.Position) > Main.CoronerSpawnDistance + 70f) drivingLoopCount++; + + if (drivingLoopCount >= 33 && drivingLoopCount <= 38) + { + Vector3 SpawnPoint; + float Heading; + bool UseSpecialID = true; + float travelDistance; + int WaitCount = 0; + while (true) + { + GetSpawnPoint(pos, out SpawnPoint, out Heading, UseSpecialID); + travelDistance = NativeFunction.Natives.CALCULATE_TRAVEL_DISTANCE_BETWEEN_POINTS(SpawnPoint.X, SpawnPoint.Y, SpawnPoint.Z, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z); + + if (Vector3.Distance(Game.LocalPlayer.Character.Position, SpawnPoint) > Main.CoronerSpawnDistance - 15f) + { + if (travelDistance < Main.CoronerSpawnDistance * 4.5f) + { + Vector3 directionFromVehicleToPed1 = (Game.LocalPlayer.Character.Position - SpawnPoint); + directionFromVehicleToPed1.Normalize(); + float HeadingToPlayer = MathHelper.ConvertDirectionToHeading(directionFromVehicleToPed1); + + if (Math.Abs(MathHelper.NormalizeHeading(Heading) - MathHelper.NormalizeHeading(HeadingToPlayer)) < 150f) break; + } + } + WaitCount++; + if (WaitCount >= 400) UseSpecialID = false; + + GameFiber.Yield(); + } + + veh.Position = SpawnPoint; + veh.Heading = Heading; + drivingLoopCount = 39; + ShowTeleportHelp(); + } + else if ((drivingLoopCount >= 70 || waitCount >= 110) || ForceTeleport) + { + Vector3 SpawnPoint = World.GetNextPositionOnStreet(pos.Around2D(15f)); + + int waitCounter = 0; + while ((SpawnPoint.Z - pos.Z < -3f) || (SpawnPoint.Z - pos.Z > 3f) || (Vector3.Distance(SpawnPoint, pos) > 25f)) + { + waitCounter++; + SpawnPoint = World.GetNextPositionOnStreet(pos.Around2D(15f)); + GameFiber.Yield(); + if (waitCounter >= 500) + { + SpawnPoint = pos.Around2D(15f); + break; + } + } + veh.Position = SpawnPoint; + Vector3 directionFromVehicleToPed = (pos - SpawnPoint); + directionFromVehicleToPed.Normalize(); + + float vehicleHeading = MathHelper.ConvertDirectionToHeading(directionFromVehicleToPed); + veh.Heading = vehicleHeading; + transportVanTeleported = true; + + break; + } + } + } + + ForceTeleport = true; + Game.HideHelp(); + while ((Vector3.Distance(pos, veh.Position) > 18f) && !transportVanTeleported) + { + Task parkNearSuspect = driver.Tasks.DriveToPosition(pos, 6f, VehicleDrivingFlags.FollowTraffic | VehicleDrivingFlags.DriveAroundVehicles | VehicleDrivingFlags.DriveAroundObjects | VehicleDrivingFlags.AllowMedianCrossing | VehicleDrivingFlags.YieldToCrossingPedestrians); + parkNearSuspect.WaitForCompletion(800); + transportVanTeleported = false; + if (Vector3.Distance(pos, veh.Position) > 80f) + { + Vector3 SpawnPoint = World.GetNextPositionOnStreet(pos.Around2D(12f)); + veh.Position = SpawnPoint; + } + } + GameFiber.Wait(600); + } + + internal static void GetSpawnPoint(Vector3 StartPoint, out Vector3 SpawnPoint1, out float Heading1, bool UseSpecialID) + { + Vector3 tmpSpawn = World.GetNextPositionOnStreet(StartPoint.Around2D(Main.CoronerSpawnDistance + 5f)); + Vector3 SpawnPoint = Vector3.Zero; + float Heading = 0; + unsafe + { + if (!UseSpecialID || !NativeFunction.Natives.GET_NTH_CLOSEST_VEHICLE_NODE_FAVOUR_DIRECTION(tmpSpawn.X, tmpSpawn.Y, tmpSpawn.Z, StartPoint.X, StartPoint.Y, StartPoint.Z, 0, out SpawnPoint, out Heading, 0, 0x40400000, 0) || !NodeExtensions.IsNodeSafe(SpawnPoint)) + { + SpawnPoint = World.GetNextPositionOnStreet(StartPoint.Around2D(Main.CoronerSpawnDistance + 5f)); + Vector3 directionFromVehicleToPed1 = (StartPoint - SpawnPoint); + directionFromVehicleToPed1.Normalize(); + Heading = MathHelper.ConvertDirectionToHeading(directionFromVehicleToPed1); + } + } + SpawnPoint1 = SpawnPoint; + Heading1 = Heading; + } + + private static void ShowTeleportHelp() + { + if (Main.UnitsTeleportToNearbyPlayerModifierKey is not Keys.None) Game.DisplayNotification(string.Format(Translation.GetString("TeleportUnit"), $"~{Main.UnitsTeleportToNearbyPlayerKey.GetInstructionalId()}~")); + else Game.DisplayNotification(string.Format(Translation.GetString("TeleportUnit"), $"~{Main.UnitsTeleportToNearbyPlayerKey.GetInstructionalId()}~ ~+~ ~{Main.UnitsTeleportToNearbyPlayerModifierKey.GetInstructionalId()}~")); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Units/Coroner/CoronerReport.cs b/DynamicLSPDFR/Units/Coroner/CoronerReport.cs new file mode 100644 index 0000000..7a5cd77 --- /dev/null +++ b/DynamicLSPDFR/Units/Coroner/CoronerReport.cs @@ -0,0 +1,82 @@ +namespace DynamicLSPDFR.Units; + +internal static class CoronerReport +{ + // 名字 名前 性別 死亡日 死因 + internal static List<(string, string, Gender, DateTime, string)> AllReports = new(); + internal static List reportItems = new(); + internal const string PASSWORD = "!]$hJPmm4tP$mY)T"; + + internal static TabView CoronerReportMenu; + private static TabSubmenuItem CoronerReportTab; + + internal static void Initialize() + { + CoronerReportMenu = new(Translation.GetString("CoronerMenu")); + CoronerReportMenu.MoneySubtitle = Translation.GetString("CoronerReportCount"); + CoronerReportMenu.Name = Game.LocalPlayer.Name; + CoronerReportMenu.PauseGame = true; + CoronerReportMenu.PlayBackgroundEffect = true; + CoronerReportMenu.Photo = new("web_lossantospolicedept", "web_lossantospolicedept", new(), new()); + CoronerReportMenu.RefreshIndex(); + + var reader = SaveReader.Create("CoronerReport"); + List<(string, string, Gender, DateTime, string)> reports = new(); + try + { + reports = reader.Read>("Report"); + foreach (var r in reports) + { + AllReports.Add(r); + + var tti = new TabTextItem(new StringBuilder(r.Item1).Append(" ").Append(r.Item2).Append(" (").Append(Translation.GetString(Enum.GetName(typeof(Gender), r.Item3))).Append(")").ToString(), string.Empty, + new StringBuilder(RSFormat.NewLine).Append(RSFormat.NewLine).Append(RSFormat.NewLine).Append(RSFormat.NewLine).Append(RSFormat.NewLine) + .Append(RSFormat.ColorBlue).Append(Translation.GetString("Name")).Append(RSFormat.Default).Append(RSFormat.NewLine) + .Append(r.Item1).Append(" ").Append(r.Item2).Append(RSFormat.NewLine) + .Append(RSFormat.ColorBlue).Append(Translation.GetString("Sex")).Append(RSFormat.Default).Append(": ").Append(Translation.GetString(Enum.GetName(typeof(Gender), r.Item3))).Append(RSFormat.NewLine) + .Append(RSFormat.NewLine) + .Append(RSFormat.ColorBlue).Append(Translation.GetString("CauseOfDeath")).Append(RSFormat.Default).Append(": ").Append(Translation.GetString(r.Item5)).Append(RSFormat.NewLine) + .Append(RSFormat.ColorBlue).Append(Translation.GetString("DiedDay")).Append(RSFormat.Default).Append(": ").Append(r.Item4.Year).Append("/").Append(r.Item4.Month).Append("/").Append(r.Item4.Day).ToString()); + + reportItems.Add(tti); + } + } + catch + { + Logger.Info("There is no data of coroner report."); + reportItems.Add(new TabTextItem(Translation.GetString("NoData"), "", "")); + } + CoronerReportMenu.AddTab(CoronerReportTab = new TabSubmenuItem("Reports", reportItems)); + + GameFiber.StartNew(ProcessMenus); + } + + private static void ProcessMenus() + { + Game.RawFrameRender += (s, e) => CoronerReportMenu.DrawTextures(e.Graphics); ; + + while (true) + { + GameFiber.Yield(); + + CoronerReportMenu.Update(); + + if (Game.IsKeyDown(Keys.U) && !UIMenu.IsAnyMenuVisible && !TabView.IsAnyPauseMenuVisible) + { + CoronerReportMenu.Visible = !CoronerReportMenu.Visible; + } + } + } + + internal static void Save((string, string, Gender, DateTime, string) data) + { + AllReports.Add(data); + var setting = new SaveSettings(); + setting.SecurityMode = SecurityMode.Aes; + setting.Password = PASSWORD; + setting.CompressionMode = CompressionMode.Gzip; + var writer = SaveWriter.Create("CoronerReport", setting); + writer.Write>("Report", AllReports); + writer.Commit(); + } +} \ No newline at end of file diff --git a/DynamicLSPDFR/Update/UpdateChecker.cs b/DynamicLSPDFR/Update/UpdateChecker.cs index b2f9cc6..1341c79 100644 --- a/DynamicLSPDFR/Update/UpdateChecker.cs +++ b/DynamicLSPDFR/Update/UpdateChecker.cs @@ -2,23 +2,24 @@ namespace DynamicLSPDFR.Update; internal static class UpdateChecker { - internal static bool HasUpdate() + internal static void CheckUpdate() { string LatestVersion = string.Empty; var webClient = new WebClient(); - // Version var uri = new Uri("https://www.lcpdfr.com/applications/downloadsng/interface/api.php?do=checkForUpdates&fileId=43022&textOnly=1"); try { LatestVersion = webClient.DownloadString(uri); - if (LatestVersion != Main.PLUGIN_VERSION_STRING) return true; - else return false; + if (LatestVersion != Main.PLUGIN_VERSION_STRING) + { + MessageExtensions.SendMessageInGame(string.Format(Translation.GetString("UpdateMessage"), Main.PLUGIN_NAME), Main.PLUGIN_NAME, Translation.GetString("UpdateAvailable")); + Game.DisplayNotification("dia_police", "dia_police", new StringBuilder(RSFormat.DarkBlue).Append(Main.PLUGIN_NAME).Append(RSFormat.Default).ToString(), new StringBuilder(RSFormat.ColorRed).Append(Translation.GetString("UpdateAvailable")).Append(RSFormat.Default).ToString(), string.Format(Translation.GetString("UpdateVersion"), Main.PLUGIN_VERSION_STRING, LatestVersion)); + } } catch (WebException ex) { Logger.Warn(ex.ToString()); - return false; } } } \ No newline at end of file diff --git a/DynamicLSPDFR/Utilities/VersionChecker.cs b/DynamicLSPDFR/Utilities/VersionChecker.cs new file mode 100644 index 0000000..ab2d722 --- /dev/null +++ b/DynamicLSPDFR/Utilities/VersionChecker.cs @@ -0,0 +1,135 @@ +namespace DynamicLSPDFR.Utilities; + +internal static class VersionChecker +{ + internal static bool AllSuccessful = true; + + internal static bool CheckLSPDFRVersion() + { + // try + // { + // if (Main.GTA5_VERSION is not null) + // { + // Game.LogTrivial(new StringBuilder("Current Game Version: ").Append(Game.ProductVersion).ToString()); + // if (Game.ProductVersion.CompareTo(Main.GTA5_VERSION) < 0) + // { + // Logger.Warn("Your GTA5 is old! Please update and restart early!", "Compatibility Warning"); + // Logger.Warn($"Supported Version of DynamicLSPDFR: {Main.GTA5_VERSION}", "Compatibility Warning"); + // Game.DisplayNotification("dia_police", "dia_police", "Please update early!", "~r~VERSION ALERT~s~", $"Your ~b~GTA5~s~'s version is ~r~old~s~. Please ~r~update your GTA5 and restart game~s~.\nSupported Version of DynamicLSPDFR: {Main.GTA5_VERSION}"); + // AllSuccessful = false; + // } + // } + // } + // catch (Exception e) + // { + // Logger.ErrorCode("VersionCheck", 10); + // Logger.Error(e.ToString(), "VersionCheck"); + // } + + // try + // { + // if (Main.LSPDFR_VERSION is not null) + // { + // if (File.Exists(Main.LSPDFR_DLL_FILE_PATH)) + // { + // var currentLSPDFRVersion = new Version(FileVersionInfo.GetVersionInfo(Main.LSPDFR_DLL_FILE_PATH).ProductVersion); + // if (currentLSPDFRVersion.CompareTo(Main.LSPDFR_VERSION) < 0) + // { + // Logger.Warn("Your LSPD First Response.dll is old! Please update and reload early!", "Compatibility Warning"); + // Logger.Warn($"Supported Version of DynamicLSPDFR: {Main.LSPDFR_VERSION}", "Compatibility Warning"); + // Game.DisplayNotification("dia_police", "dia_police", "Please update early!", "~r~VERSION ALERT~s~", $"Your ~b~LSPDFR~s~'s version is ~r~old~s~. Please ~r~update your LSPDFR and reload~s~.\nSupported Version of DynamicLSPDFR: {Main.LSPDFR_VERSION}"); + // AllSuccessful = false; + // } + // } + // } + // } + // catch (Exception e) + // { + // Logger.ErrorCode("VersionCheck", 11); + // Logger.Error(e.ToString(), "VersionCheck"); + // } + + // try + // { + // if (Main.MINIMUM_RAGE_PLUGIN_HOOK_VERSION is not null) + // { + // if (File.Exists(Main.RPH_APPLICATION_PATH)) + // { + // var currentRPHVersion = new Version(FileVersionInfo.GetVersionInfo(Main.RPH_APPLICATION_PATH).ProductVersion); + // if (currentRPHVersion.CompareTo(Main.MINIMUM_RAGE_PLUGIN_HOOK_VERSION) >= 0) + // { + // Logger.Warn("Your RagePluginHook is old! Please update and restart game early!", "Compatibility Warning"); + // Logger.Warn($"Supported Version of DynamicLSPDFR: {Main.MINIMUM_RAGE_PLUGIN_HOOK_VERSION} or higher", "Compatibility Warning"); + // Game.DisplayNotification("dia_police", "dia_police", "Please update early!", "~r~VERSION ALERT~s~", $"Your ~b~RAGEPluginHook~s~'s version is ~r~old~s~. Please ~r~update your RAGEPluginHook and restart game~s~.\nSupported Version of DynamicLSPDFR: {Main.MINIMUM_RAGE_PLUGIN_HOOK_VERSION}"); + // AllSuccessful = false; + // } + // } + // } + // } + // catch (Exception e) + // { + // Logger.ErrorCode("VersionCheck", 12); + // Logger.Error(e.ToString(), "VersionCheck"); + // } + + // try + // { + // if (Main.RAGE_NATIVE_UI_DLL_VERSION is not null) + // { + // if (File.Exists(Main.RAGE_NATIVE_UI_DLL_FILE_PATH)) + // { + // var currentRAGENativeUIVersion = new Version(FileVersionInfo.GetVersionInfo(Main.RAGE_NATIVE_UI_DLL_FILE_PATH).ProductVersion); + // if (currentRAGENativeUIVersion.CompareTo(Main.RAGE_NATIVE_UI_DLL_VERSION) < 0) + // { + // Logger.Warn("Your RAGENativeUI.dll is old! Please update and reload early!", "Compatibility Warning"); + // Logger.Warn($"Supported Version of DynamicLSPDFR: {Main.RAGE_NATIVE_UI_DLL_VERSION}", "Compatibility Warning"); + // Game.DisplayNotification("dia_police", "dia_police", "Please update early!", "~r~VERSION ALERT~s~", $"Your ~b~RAGE Native UI~s~'s version is ~r~old~s~. Please ~r~update your RAGE Native UI and restart game~s~.\nSupported Version of DynamicLSPDFR: {Main.RAGE_NATIVE_UI_DLL_VERSION}"); + // AllSuccessful = false; + // } + // } + // else + // { + // Game.LogTrivial("RAGENativeUI.dll isn't installed. Please install RAGENativeUI."); + // Game.DisplayNotification("dia_police", "dia_police", "~r~Emergency Alert~s~", "", $"You ~r~haven't installed~s~ the ~b~RAGENativeUI.dll~s~ yet! Please ~g~install and reload LSPDFR!~s~\nSupported Version of DynamicLSPDFR: {Main.RAGE_NATIVE_UI_DLL_VERSION}"); + // AllSuccessful = false; + // } + // } + // } + // catch (Exception e) + // { + // Logger.ErrorCode("VersionCheck", 13); + // Logger.Error(e.ToString(), "VersionCheck"); + // } + + // try + // { + // if (Main.NEWTONSOFT_JSON_DLL_VERSION is not null) + // { + // if (File.Exists(Main.NEWTONSOFT_JSON_DLL_FILE_PATH)) + // { + // var currentNewtonsoftJsonVersion = new Version(FileVersionInfo.GetVersionInfo(Main.NEWTONSOFT_JSON_DLL_FILE_PATH).ProductVersion); + // if (currentNewtonsoftJsonVersion.CompareTo(Main.NEWTONSOFT_JSON_DLL_VERSION) < 0) + // { + // Logger.Warn("Your Newtonsoft.Json.dll is old! Please update and reload early!", "Compatibility Warning"); + // Logger.Warn($"Supported Version of DynamicLSPDFR: {Main.NEWTONSOFT_JSON_DLL_VERSION}", "Compatibility Warning"); + // Game.DisplayNotification("dia_police", "dia_police", "Please update early!", "~r~VERSION ALERT~s~", $"Your ~b~Newtonsoft.Json~s~'s version is ~r~old~s~. Please ~r~update your Newtonsoft.Json and restart game~s~.\nSupported Version of DynamicLSPDFR: {Main.NEWTONSOFT_JSON_DLL_VERSION}"); + // AllSuccessful = false; + // } + // } + // else + // { + // Game.LogTrivial("Newtonsoft.Json.dll isn't installed. Please install Newtonsoft.Json."); + // Game.DisplayNotification("dia_police", "dia_police", "~r~Emergency Alert~s~", "", $"You ~r~haven't installed~s~ the ~b~Newtonsoft.Json.dll~s~ yet! Please ~g~install and reload LSPDFR!~s~\nSupported Version of DynamicLSPDFR: {Main.NEWTONSOFT_JSON_DLL_VERSION}"); + // AllSuccessful = false; + // } + // } + // } + // catch (Exception e) + // { + // Logger.ErrorCode("VersionCheck", 14); + // Logger.Error(e.ToString(), "VersionCheck"); + // } + + return AllSuccessful; + } +} \ No newline at end of file diff --git a/PowerShell/CopyFiles-Confuse.ps1 b/PowerShell/CopyFiles-Confuse.ps1 new file mode 100644 index 0000000..af8f7d3 --- /dev/null +++ b/PowerShell/CopyFiles-Confuse.ps1 @@ -0,0 +1,22 @@ +Start-Sleep -Seconds 1 +$Directory = "DynamicLSPDFR" +$GTA5 = $env:GrandTheftAutoV # Environment Variables (GrandTheftAutoV) + +# Newtonsoft.Json.dll +Copy-Item $Directory/Build/Newtonsoft.Json.dll $GTA5 -Force -ErrorAction SilentlyContinue +Write-Host "Newtonsoft.Json.dll was moved!" -ForegroundColor DarkCyan +# RAGENativeUI.dll +Copy-Item $Directory/Build/RAGENativeUI.dll $GTA5 -Force -ErrorAction SilentlyContinue +Write-Host "RAGENativeUI.dll was moved!" -ForegroundColor DarkCyan +# DynamicLSPDFR.dll +Copy-Item $Directory/Build/Confused/DynamicLSPDFR.dll $GTA5/Plugins/LSPDFR -Force -ErrorAction SilentlyContinue +Write-Host "DynamicLSPDFR.dll was moved!" -ForegroundColor DarkCyan +# DynamicLSPDFR.ini +Copy-Item $Directory/DynamicLSPDFR.ini $GTA5/Plugins/LSPDFR -Force -ErrorAction SilentlyContinue +Write-Host "DynamicLSPDFR.ini was moved!" -ForegroundColor DarkCyan +# Sound files +Copy-Item $Directory/Sounds/DynamicLSPDFR/ $GTA5/LSPDFR/audio/scanner/ -Force -Recurse -ErrorAction SilentlyContinue +Write-Host "Sound files were moved!" -ForegroundColor DarkCyan +# Banner.png +Copy-Item $Directory/Resources/Images/Banner.png $GTA5/Plugins/LSPDFR/DynamicLSPDFR -Force -ErrorAction SilentlyContinue +Write-Output "Banner.png was moved!" \ No newline at end of file diff --git a/PowerShell/CopyFiles.ps1 b/PowerShell/CopyFiles.ps1 index 1dde807..3ad2a4c 100644 --- a/PowerShell/CopyFiles.ps1 +++ b/PowerShell/CopyFiles.ps1 @@ -3,20 +3,20 @@ $Directory = "DynamicLSPDFR" $GTA5 = $env:GrandTheftAutoV # Environment Variables (GrandTheftAutoV) # Newtonsoft.Json.dll -Copy-Item $Directory/Build/Newtonsoft.Json.dll $GTA5 -Force +Copy-Item $Directory/Build/Newtonsoft.Json.dll $GTA5 -Force -ErrorAction SilentlyContinue Write-Host "Newtonsoft.Json.dll was moved!" -ForegroundColor DarkCyan # RAGENativeUI.dll -Copy-Item $Directory/Build/RAGENativeUI.dll $GTA5 -Force +Copy-Item $Directory/Build/RAGENativeUI.dll $GTA5 -Force -ErrorAction SilentlyContinue Write-Host "RAGENativeUI.dll was moved!" -ForegroundColor DarkCyan # DynamicLSPDFR.dll -Copy-Item $Directory/Build/Confused/DynamicLSPDFR.dll $GTA5/Plugins/LSPDFR -Force +Copy-Item $Directory/Build/DynamicLSPDFR.dll $GTA5/Plugins/LSPDFR -Force -ErrorAction SilentlyContinue Write-Host "DynamicLSPDFR.dll was moved!" -ForegroundColor DarkCyan # DynamicLSPDFR.ini -Copy-Item $Directory/DynamicLSPDFR.ini $GTA5/Plugins/LSPDFR -Force +Copy-Item $Directory/DynamicLSPDFR.ini $GTA5/Plugins/LSPDFR -Force -ErrorAction SilentlyContinue Write-Host "DynamicLSPDFR.ini was moved!" -ForegroundColor DarkCyan # Sound files -Copy-Item $Directory/Sounds/DynamicLSPDFR/ $GTA5/LSPDFR/audio/scanner/ -Force -Recurse +Copy-Item $Directory/Sounds/DynamicLSPDFR/ $GTA5/LSPDFR/audio/scanner/ -Force -Recurse -ErrorAction SilentlyContinue Write-Host "Sound files were moved!" -ForegroundColor DarkCyan # Banner.png -Copy-Item $Directory/Resources/Images/Banner.png $GTA5/Plugins/LSPDFR/DynamicLSPDFR -Force +Copy-Item $Directory/Resources/Images/Banner.png $GTA5/Plugins/LSPDFR/DynamicLSPDFR -Force -ErrorAction SilentlyContinue Write-Output "Banner.png was moved!" \ No newline at end of file diff --git a/Public/DynamicLSPDFR b/Public/DynamicLSPDFR index 25335df..6a98407 160000 --- a/Public/DynamicLSPDFR +++ b/Public/DynamicLSPDFR @@ -1 +1 @@ -Subproject commit 25335dfb9dc1c96b096f1ce9b43ced9245e8dd79 +Subproject commit 6a984072bc270cb490aed2187578eed5149012c4 diff --git a/Public/DynamicLSPDFR.wiki b/Public/DynamicLSPDFR.wiki index 1d27706..1257a38 160000 --- a/Public/DynamicLSPDFR.wiki +++ b/Public/DynamicLSPDFR.wiki @@ -1 +1 @@ -Subproject commit 1d27706212e5b8da8597d7abb29b993ad5054018 +Subproject commit 1257a38aa137f34da1d685b206fc3a2b9b4f59a8 diff --git a/ReleaseBuild-Confused.ps1 b/ReleaseBuild-Confused.ps1 new file mode 100644 index 0000000..6822180 --- /dev/null +++ b/ReleaseBuild-Confused.ps1 @@ -0,0 +1,15 @@ +Write-Host "-------- Build as the Release Edition --------" -ForegroundColor Magenta +Write-Host "-------- Comfused Enabled --------" -ForegroundColor Green +Start-Sleep -Milliseconds 250 +.\PowerShell\Release.ps1 +Write-Host "-------- Build Completed --------" -ForegroundColor Green +Write-Host "-------- Start Obfuscation --------" -ForegroundColor Blue +Start-Sleep -Milliseconds 250 +.\PowerShell\Obfuscation.ps1 +Write-Host "-------- Obfuscation Completed --------" -ForegroundColor Green +Write-Host "-------- Copy Files to GTA5 --------" -ForegroundColor Blue +Start-Sleep -Milliseconds 250 +.\PowerShell\CopyFiles-Confuse.ps1 +Start-Sleep -Milliseconds 250 +Write-Host "-------- Copy Completed --------" -ForegroundColor Green +.\PowerShell\Completed.ps1 \ No newline at end of file diff --git a/ReleaseBuild.ps1 b/ReleaseBuild.ps1 index d8e537a..68daae7 100644 --- a/ReleaseBuild.ps1 +++ b/ReleaseBuild.ps1 @@ -1,11 +1,9 @@ Write-Host "-------- Build as the Release Edition --------" -ForegroundColor Magenta +Write-Host "-------- Comfused Disabled --------" -ForegroundColor Red Start-Sleep -Milliseconds 250 .\PowerShell\Release.ps1 Write-Host "-------- Build Completed --------" -ForegroundColor Green -Write-Host "-------- Start Obfuscation --------" -ForegroundColor Blue -Start-Sleep -Milliseconds 250 -.\PowerShell\Obfuscation.ps1 -Write-Host "-------- Obfuscation Completed --------" -ForegroundColor Green +Write-Host "-------- Skip Obfuscation --------" -ForegroundColor Blue Write-Host "-------- Copy Files to GTA5 --------" -ForegroundColor Blue Start-Sleep -Milliseconds 250 .\PowerShell\CopyFiles.ps1 diff --git a/ReleaseZip.ps1 b/ReleaseZip-Confused.ps1 similarity index 88% rename from ReleaseZip.ps1 rename to ReleaseZip-Confused.ps1 index 58350f2..d640ee9 100644 --- a/ReleaseZip.ps1 +++ b/ReleaseZip-Confused.ps1 @@ -1,4 +1,5 @@ Write-Host "-------- Build as the Release Zip Edition --------" -ForegroundColor Magenta +Write-Host "-------- Comfused Enabled --------" -ForegroundColor Green Start-Sleep -Milliseconds 250 .\PowerShell\Release.ps1 Write-Host "-------- Build Completed --------" -ForegroundColor Green @@ -8,7 +9,7 @@ Start-Sleep -Milliseconds 250 Write-Host "-------- Obfuscation Completed --------" -ForegroundColor Green Write-Host "-------- Copy Files to GTA5 --------" -ForegroundColor Blue Start-Sleep -Milliseconds 250 -.\PowerShell\CopyFiles.ps1 +.\PowerShell\CopyFiles-Confuse.ps1 Write-Host "-------- Copy Completed --------" -ForegroundColor Green Write-Host "-------- Compression Start --------" -ForegroundColor Blue Start-Sleep -Milliseconds 250 diff --git a/Translate/CalloutDescriptions.xlsx b/Translate/CalloutDescriptions.xlsx index e5396c3..342f029 100644 Binary files a/Translate/CalloutDescriptions.xlsx and b/Translate/CalloutDescriptions.xlsx differ diff --git a/Translate/Callouts.xlsx b/Translate/Callouts.xlsx index e9b53f9..ba2b0ad 100644 Binary files a/Translate/Callouts.xlsx and b/Translate/Callouts.xlsx differ diff --git a/Translate/Conversations.xlsx b/Translate/Conversations.xlsx index 4bdca92..c93a9b4 100644 Binary files a/Translate/Conversations.xlsx and b/Translate/Conversations.xlsx differ diff --git a/Translate/Main.xlsx b/Translate/Main.xlsx index 3d93233..b58a4a2 100644 Binary files a/Translate/Main.xlsx and b/Translate/Main.xlsx differ diff --git a/Translate/UIMenu.xlsx b/Translate/UIMenu.xlsx index f603930..84702c7 100644 Binary files a/Translate/UIMenu.xlsx and b/Translate/UIMenu.xlsx differ