From fc1a2443180c1e0d40c7666e5a46e1b632926ed1 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:41:22 +0100 Subject: [PATCH 01/15] Update HEMTT & tools --- .github/CODEOWNERS | 3 + .github/labels.json | 38 +++++++ .github/release-drafter.yml | 33 ++++++ .github/workflows/arma.yml | 33 +++--- .github/workflows/release-drafter.yml | 16 +++ .github/workflows/release.yml | 33 ++++++ .hemtt/hooks/pre_build/set_version.rhai | 14 +++ .hemtt/launch.toml | 43 ++++++++ .hemtt/lints.toml | 5 + .hemtt/project.toml | 31 +----- addons/main/ui/logo_sm_ca.paa | Bin 0 -> 49205 bytes mod.cpp | 3 + tools/Publish.ps1 | 28 ----- tools/Set-Version.ps1 | 10 -- tools/return_checker.py | 141 ++++++++++++++++++++++++ tools/sqf_validator.py | 2 +- tools/stringtable_validator.py | 15 ++- 17 files changed, 355 insertions(+), 93 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/labels.json create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/release-drafter.yml create mode 100644 .github/workflows/release.yml create mode 100644 .hemtt/hooks/pre_build/set_version.rhai create mode 100644 .hemtt/launch.toml create mode 100644 .hemtt/lints.toml create mode 100644 addons/main/ui/logo_sm_ca.paa delete mode 100644 tools/Publish.ps1 delete mode 100644 tools/Set-Version.ps1 create mode 100644 tools/return_checker.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..e417650e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners +# +* @ArmaForces/sqf-devs diff --git a/.github/labels.json b/.github/labels.json new file mode 100644 index 00000000..67b11451 --- /dev/null +++ b/.github/labels.json @@ -0,0 +1,38 @@ +[ + { + "name": "bug", + "color": "#d73a4a", + "description": "Something isn't working" + }, + { + "name": "bugfix", + "color": "#52ed47", + "description": "Fixes something wasn't working" + }, + { + "name": "documentation", + "color": "#0075ca", + "description": "Improvements or additions to documentation" + }, + { + "name": "duplicate", + "color": "#cfd3d7", + "description": "This issue or pull request already exists" + }, + { + "name": "enhancement", + "color": "#a2eeef", + "description": "New feature or request" + }, + { + "name": "ignore changelog", + "color": "#fff", + "description": "Do not add to changelog" + }, + { + "name": "scenario", + "color": "#3BC4B8", + "description": "Improvements or additions to a scenario" + } +] + diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..87de2055 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,33 @@ +branches: + - master + +name-template: 'v$NEXT_PATCH_VERSION' +tag-template: 'v$NEXT_PATCH_VERSION' + +categories: + - title: '**ADDED:**' + labels: + - feature + - title: '**FIXED:**' + labels: + - bugfix + - title: '**CHANGED:**' + labels: + - cleanup + - enhancement + +exclude-labels: + - 'ignore changelog' + +change-template: '- $TITLE (#$NUMBER)' +template: | + _ArmaForces SerialKillers release._ + + ## Change Log Summary + + $CHANGES + +replacers: + # Category titles + - search: '/\#\# (\*\*(ADDED|FIXED|CHANGED):\*\*)/g' + replace: '$1' diff --git a/.github/workflows/arma.yml b/.github/workflows/arma.yml index fef1c598..224ab9f0 100644 --- a/.github/workflows/arma.yml +++ b/.github/workflows/arma.yml @@ -14,6 +14,8 @@ jobs: uses: actions/checkout@master - name: Validate SQF run: python3 tools/sqf_validator.py + - name: Validate Return Types + run: python3 tools/return_checker.py - name: Validate Config run: python3 tools/config_style_checker.py - name: Validate Stringtables @@ -21,26 +23,17 @@ jobs: - name: Check for BOM uses: arma-actions/bom-check@master - lint: + build-linux: runs-on: ubuntu-latest steps: - name: Checkout the source code - uses: actions/checkout@master - - name: Lint (sqflint) - uses: arma-actions/sqflint@master - continue-on-error: true # No failure due to many false-positives - -# build: -# runs-on: ubuntu-latest -# steps: -# - name: Checkout the source code -# uses: actions/checkout@master -# - name: Build using HEMTT -# uses: arma-actions/hemtt@master -# with: -# command: build --release --ci -# https://github.com/actions/upload-artifact/issues/3#issuecomment-524442814 -# - uses: actions/upload-artifact@master -# with: -# name: armaforces_mods_VERSION -# path: releases/VERSION + uses: actions/checkout@v4 + - name: Setup HEMTT + uses: arma-actions/hemtt@v1 + - name: Run HEMTT build + run: hemtt build + - uses: actions/upload-artifact@v4 + with: + name: afsk_${{ github.sha }}-nobin + path: .hemttout/@* + include-hidden-files: true # Because .hemttout is a hidden directory diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000..1afdfef0 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,16 @@ +name: Release Drafter + +on: + push: + branches: + - master + +jobs: + draft: + runs-on: ubuntu-latest + steps: + - name: Release Drafter + if: github.repository == 'ArmaForces/SerialKillers' + uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..bdea6c93 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,33 @@ +name: Release + +on: + release: + types: + - published + +jobs: + build_addon: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set VERSION env + run: echo VERSION=${GITHUB_REF:11} >> $GITHUB_ENV + - name: Setup HEMTT + uses: arma-actions/hemtt@v1 + - name: Run HEMTT release + run: hemtt release + # Upload to GitHub + - uses: softprops/action-gh-release@v1 + with: + files: 'releases/afsk-${{ env.VERSION }}-*.zip' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Upload to Steam Workshop + - uses: arma-actions/workshop-upload@v1 + with: + itemId: '1993094302' # Id of item to update + contentPath: '.hemttout/release' + changelog: 'https://github.com/ArmaForces/SerialKillers/releases/tag/v${{ env.VERSION }}' + env: + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }} diff --git a/.hemtt/hooks/pre_build/set_version.rhai b/.hemtt/hooks/pre_build/set_version.rhai new file mode 100644 index 00000000..f26f229d --- /dev/null +++ b/.hemtt/hooks/pre_build/set_version.rhai @@ -0,0 +1,14 @@ + +let modCpp = HEMTT_VFS + .join("mod.cpp") + .open_file() + .read() +; + +modCpp.replace("0.0.0", HEMTT.project().version().to_string_short()); + +HEMTT_VFS + .join("mod.cpp") + .create_file() + .write(modCpp) +; diff --git a/.hemtt/launch.toml b/.hemtt/launch.toml new file mode 100644 index 00000000..3fa1131f --- /dev/null +++ b/.hemtt/launch.toml @@ -0,0 +1,43 @@ +[default] +workshop = [ + "450814997", # CBA_A3 + "2369477168", # ADT +] +parameters = [ + "-name=dev_sk", +] + +[ace] +extends = "default" +workshop = [ + "463939057", # ACE +# "766491311", # KKA3 ACE Extension +] + +[cup] +extends = "default" +workshop = [ + "583496184", # CUP Terrains - Core + "583544987", # CUP Terrains - Maps + "497660133", # CUP Weapons + "497661914", # CUP Units + "541888371", # CUP Vehicles +] + +[vn] +extends = "default" +dlc = [ + "S.O.G. Prairie Fire", +] + +[ww2] +extends = "default" +dlc = [ + "Spearhead 1944", +] + +[gm] +extends = "default" +dlc = [ + "Global Mobilization", +] diff --git a/.hemtt/lints.toml b/.hemtt/lints.toml new file mode 100644 index 00000000..a8fd636e --- /dev/null +++ b/.hemtt/lints.toml @@ -0,0 +1,5 @@ +[sqf.command_case] +options.ignore = [ + "EAST", + "WEST", +] diff --git a/.hemtt/project.toml b/.hemtt/project.toml index f6f7a9be..ba34c73b 100644 --- a/.hemtt/project.toml +++ b/.hemtt/project.toml @@ -1,3 +1,4 @@ + name = "ArmaForces SerialKillers" mainprefix = "z" prefix = "afsk" @@ -16,33 +17,3 @@ author = "ArmaForces" [version] path = "addons/main/script_version.hpp" - -[asc] -exclude = [ - ".inc.sqf" -] - -[hemtt.launch] -workshop = [ - "450814997", # CBA_A3 - "2369477168", # ADT -] -parameters = [ - "-name=dev_sk", - "-window", -] - -[hemtt.launch.cup] -workshop = [ - "450814997", # CBA_A3 - "2369477168", # ADT - "583496184", # CUP Terrains - Core - "583544987", # CUP Terrains - Maps - "497660133", # CUP Weapons - "497661914", # CUP Units - "541888371", # CUP Vehicles -] -parameters = [ - "-name=dev_sk", - "-window", -] diff --git a/addons/main/ui/logo_sm_ca.paa b/addons/main/ui/logo_sm_ca.paa new file mode 100644 index 0000000000000000000000000000000000000000..37d7faf8c192c828b450d0d40fbf9eae4a1f8721 GIT binary patch literal 49205 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 W&%Y&qR4@*O4AowCIAE;d_ul{rUnfie literal 0 HcmV?d00001 diff --git a/mod.cpp b/mod.cpp index 4328e322..9e86dd3d 100644 --- a/mod.cpp +++ b/mod.cpp @@ -4,5 +4,8 @@ author = "ArmaForces"; url = "https://github.com/armaforces/serialkillers/"; action = "https://armaforces.com/"; actionName = "Website"; +logo = "\z\afwg\addons\main\ui\logo_sm_ca.paa"; +logoOver = "\z\afwg\addons\main\ui\logo_sm_ca.paa"; +overviewPicture = "\z\afwg\addons\main\ui\logo_sm_ca.paa"; tooltip = "ArmaForces SerialKillers"; description = "ArmaForces SerialKillers gamemode developed by 3Mydlo3."; diff --git a/tools/Publish.ps1 b/tools/Publish.ps1 deleted file mode 100644 index 97fbeace..00000000 --- a/tools/Publish.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -param ( - [string] $version, - [string] $workshopId, - [string] $addonDir -) - -$choice = Read-Host -Prompt "Do you want to publish '$version' on Steam Workshop? (y/N)" -if ('y' -ne $choice.ToLower()) { - Write-Host "Skipping Steam Workshop upload" - Exit -} - -try { - $publisherPath = (Get-ItemProperty -Path Registry::"HKEY_CURRENT_USER\Software\Bohemia Interactive\publisher" -ErrorAction Stop).path -} catch { - Throw "Can't find Publisher path in registry" -} - -$modPath = $PSScriptRoot + "/../releases/$version/$addonDir" | Resolve-Path - -$publisherArguments = @( - "update", - "/id:$workshopId", - "/changeNote:""Automatic mod upload""", - "/path:""$modPath""" -) - -Start-Process -FilePath "$publisherPath\PublisherCmd.exe" -NoNewWindow -Wait -ArgumentList $publisherArguments diff --git a/tools/Set-Version.ps1 b/tools/Set-Version.ps1 deleted file mode 100644 index 6c71fcca..00000000 --- a/tools/Set-Version.ps1 +++ /dev/null @@ -1,10 +0,0 @@ -param ( - [string] $version, - [string] $addonDir -) - -$modCppPath = $PSScriptRoot + "/../releases/$version/$addonDir/mod.cpp" - -$replaced = (Get-Content $modCppPath) -replace "0.0.0", "$version" - -$replaced | Out-File $modCppPath diff --git a/tools/return_checker.py b/tools/return_checker.py new file mode 100644 index 00000000..0999077e --- /dev/null +++ b/tools/return_checker.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 + +import fnmatch +import os +import re +import sys + + +def get_files(): + # Allow running from root directory and tools directory + root_dir = ".." + if os.path.exists("addons"): + root_dir = "." + + sqf_files = [] + + for root, _, files in os.walk(root_dir): + for file in fnmatch.filter(files, "*.sqf"): + sqf_files.append(os.path.join(root, file)) + + sqf_files.sort() + + return sqf_files + + +def filter_files(filepaths): + filtered_files = [] + + # Return only files that have a docblock + for filepath in filepaths: + with open(filepath, 'r') as file_contents: + for line in file_contents: + contents = line.strip() + + # A possible docblock starts + if contents.startswith('/*'): + # Find the `* Return Value:` comment + lines = list(map( + # Remove \n from all the lines + (lambda s: s.strip()), file_contents.readlines() + )) + + return_value_comment_index = lines.index('* Return Value:') + return_value_index = return_value_comment_index + 1 + + # Drop the first two characters (e.g. `* `) so it returns the return type + return_value = lines[return_value_index][2:] + + filtered_files.append([filepath, return_value]) + + break + + return filtered_files + + +def get_last_line(filepath): + with open(filepath, 'r') as file_contents: + lines = file_contents.readlines() + last_line = lines[-1].strip() + + # Handle multiple blank lines at the end of the file + if last_line == "": + i = -2 + + while lines[i].strip() == "": + i -= 1 + + return lines[i].strip() + return last_line + + +def check_last_character(filepath, return_value): + last_line = get_last_line(filepath) + last_line_character = last_line[-1] + + # If return type is None and the last line has a semicolon OR the last thing is just the nil keyword OR last thing is a closing bracket + if return_value == 'None' and (last_line_character == ';' or last_line == 'nil' or last_line == '};'): + return True + elif return_value != 'None' and (last_line_character != ';' or last_line == '};'): + return True + else: + return False + + +def get_expected_last_line(last_line, return_value): + last_line_character = last_line[-1] + + if return_value == 'None': + # If last character is a letter or a number + if re.search(r'[A-Za-z0-9]', last_line_character): + return '{};'.format(last_line) + else: + return 'nil' + else: + if last_line_character == ';': + return last_line[:-1] + + return 'Unknown' + + +def main(): + print('Validating Return Types') + print('-----------------------') + + bad_files = [] + + files = get_files() + filtered_files = filter_files(files) + + for file_details in filtered_files: + filepath, return_value = file_details + + status = check_last_character(filepath, return_value) + + if not status: + bad_files.append( + [filepath, return_value, get_last_line(filepath)]) + + error_count = len(bad_files) + print('Found {} error(s)'.format(error_count)) + + for bad_file in bad_files: + filepath, return_value, last_line = bad_file + + expected_last_line = get_expected_last_line(last_line, return_value) + + print('\nERROR: In file {}'.format(filepath)) + print('Incorrect return type, expected `{}`'.format(return_value)) + print('Found line `{}`'.format(last_line)) + print('Expected line `{}`'.format(expected_last_line)) + + if error_count: + print('\nReturn Validation FAILED') + else: + print('\nReturn Validation PASSED') + + return error_count + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/sqf_validator.py b/tools/sqf_validator.py index 6da3364b..a76b9793 100644 --- a/tools/sqf_validator.py +++ b/tools/sqf_validator.py @@ -12,7 +12,7 @@ open = codecs.open def validKeyWordAfterCode(content, index): - keyWords = ["for", "do", "count", "each", "forEach", "else", "and", "not", "isEqualTo", "isNotEqualTo", "in", "call", "spawn", "execVM", "catch", "param", "select", "apply"]; + keyWords = ["for", "do", "count", "each", "forEach", "else", "and", "not", "isEqualTo", "in", "call", "spawn", "execVM", "catch", "param", "select", "apply"]; for word in keyWords: try: subWord = content.index(word, index, index+len(word)) diff --git a/tools/stringtable_validator.py b/tools/stringtable_validator.py index 55484730..207f09d0 100644 --- a/tools/stringtable_validator.py +++ b/tools/stringtable_validator.py @@ -16,7 +16,7 @@ ######## GLOBALS ######### -PROJECT_NAME = "AFSK" +PROJECT_NAME = "AFWG" ########################## @@ -53,9 +53,16 @@ def check_stringtable(filepath): print(" ERROR: Package name attribute '{}' is all lowercase, should be in titlecase.".format(package_name)) errors += 1 - if package_name.lower() != os.path.basename(os.path.dirname(filepath)): - print(" ERROR: Package name attribute '{}' does not match the component folder name.".format(package_name)) - errors += 1 + component_folder_name = os.path.basename(os.path.dirname(filepath)) + + if package_name.lower() != component_folder_name: + parent_component_folder_name = os.path.basename(os.path.dirname(os.path.dirname(filepath))) + subcomponent_name = f"{parent_component_folder_name}_{component_folder_name}" + if package_name.lower() != subcomponent_name: + print(" ERROR: Package name attribute '{}' does not match any of component folder name '{}' and subcomponent '{}'.".format(package_name, component_folder_name, subcomponent_name)) + errors += 1 + else: + print(f" INFO: Detected subaddon '{subcomponent_name}' used in Package name attribute.") # Get all keys contained in the stringtable keys = package.findall("Key") From 628dbc420db57aad84d6b286c2d0be5208ef04b1 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:43:50 +0100 Subject: [PATCH 02/15] Fix unused format param --- addons/civilian/functions/fnc_civilianKilledMarker.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/civilian/functions/fnc_civilianKilledMarker.sqf b/addons/civilian/functions/fnc_civilianKilledMarker.sqf index ce47606b..eee5ffa5 100644 --- a/addons/civilian/functions/fnc_civilianKilledMarker.sqf +++ b/addons/civilian/functions/fnc_civilianKilledMarker.sqf @@ -18,7 +18,7 @@ params ["_unit", "_time"]; -private _markerName = format ["killed_civilian_%1_%2", _unit]; +private _markerName = format ["killed_civilian_%1", _unit]; private _markerText = format ["%1", _time]; private _marker = createMarkerLocal [_markerName, getPosATL _unit]; _marker setMarkerTypeLocal "mil_objective"; From e3571cc0d9cc8487973c650f6bd00d65cbc7150e Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:45:42 +0100 Subject: [PATCH 03/15] Config duplication --- addons/equipment/CfgSerialKillers.hpp | 3 --- addons/vehicles/CfgVehicles.hpp | 2 -- 2 files changed, 5 deletions(-) diff --git a/addons/equipment/CfgSerialKillers.hpp b/addons/equipment/CfgSerialKillers.hpp index b1065952..b73fd38b 100644 --- a/addons/equipment/CfgSerialKillers.hpp +++ b/addons/equipment/CfgSerialKillers.hpp @@ -255,7 +255,6 @@ class CfgSerialKillers class ACE_microDAGR {}; class ACE_DAGR {}; class ACE_CableTie {}; - class ACE_HandFlare_White {}; class ACE_Flashlight_XL50 {}; class ACE_Flashlight_KSF1 {}; class ACE_Flashlight_MX991 {}; @@ -394,7 +393,6 @@ class CfgSerialKillers availableInStash = 1; }; class rhsusf_acc_leupoldmk4_2 : rhs_weap_M107 {}; - class rhsusf_acc_eotech_552 : rhs_weap_M107 {}; /* Launchers */ class rhs_weap_panzerfaust60 @@ -731,7 +729,6 @@ class CfgSerialKillers class U_BG_Guerilla2_1 {}; class U_BG_Guerilla2_3 {}; class U_C_Journalist {}; - class U_Marshal {}; class U_C_IDAP_Man_casual_F {}; class U_C_IDAP_Man_Jeans_F {}; class U_C_IDAP_Man_Tee_F {}; diff --git a/addons/vehicles/CfgVehicles.hpp b/addons/vehicles/CfgVehicles.hpp index ddf7fd88..0764da21 100644 --- a/addons/vehicles/CfgVehicles.hpp +++ b/addons/vehicles/CfgVehicles.hpp @@ -4,8 +4,6 @@ class CfgVehicles { class Car_F; - class Hatchback_01_base_F; - class Hatchback_01_sport_base_F; class C_Hatchback_01_F; class C_Hatchback_01_sport_F; From 0e808ff3eda09e6a295bc4fc2cd078d2b475315f Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:47:27 +0100 Subject: [PATCH 04/15] Remove unnecessary macro padding --- addons/civilian/functions/fnc_createCivilian.sqf | 2 +- addons/civilian_statemachine/functions/fnc_getOut.sqf | 2 +- .../civilian_statemachine/functions/fnc_moveToVehicle.sqf | 2 +- addons/common/functions/fnc_getNearestCityLocation.sqf | 2 +- addons/common/functions/fnc_getNearestLocation.sqf | 2 +- addons/jail/functions/fnc_addReleaseAction.sqf | 4 ++-- addons/police/functions/fnc_equipmentScoreCheck.sqf | 6 +++--- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/civilian/functions/fnc_createCivilian.sqf b/addons/civilian/functions/fnc_createCivilian.sqf index 0b279d02..6731df01 100644 --- a/addons/civilian/functions/fnc_createCivilian.sqf +++ b/addons/civilian/functions/fnc_createCivilian.sqf @@ -22,7 +22,7 @@ private _unit = selectRandom GVAR(units); private _civilian = _newGroup createUnit [_unit, _position, [], 0, "NONE"]; if (_civilian isEqualTo objNull) exitWith { - WARNING_2("Failed creating civilian %1 at %2", _unit, _position); + WARNING_2("Failed creating civilian %1 at %2",_unit,_position); }; [_civilian] call FUNC(initCivilian); diff --git a/addons/civilian_statemachine/functions/fnc_getOut.sqf b/addons/civilian_statemachine/functions/fnc_getOut.sqf index 5382deb6..5a20e508 100644 --- a/addons/civilian_statemachine/functions/fnc_getOut.sqf +++ b/addons/civilian_statemachine/functions/fnc_getOut.sqf @@ -25,4 +25,4 @@ private _waypoint = _group addWaypoint [_vehicle, 0]; _waypoint waypointAttachVehicle _vehicle; _waypoint setWaypointType "GETOUT"; -TRACE_2("Group %1 getting out of a vehicle %2", _group, _vehicle); +TRACE_2("Group %1 getting out of a vehicle %2",_group,_vehicle); diff --git a/addons/civilian_statemachine/functions/fnc_moveToVehicle.sqf b/addons/civilian_statemachine/functions/fnc_moveToVehicle.sqf index 75cfeab9..1a4fb248 100644 --- a/addons/civilian_statemachine/functions/fnc_moveToVehicle.sqf +++ b/addons/civilian_statemachine/functions/fnc_moveToVehicle.sqf @@ -25,4 +25,4 @@ private _waypoint = _group addWaypoint [_vehicle, 0]; _waypoint waypointAttachVehicle _vehicle; _waypoint setWaypointType "GETIN"; -TRACE_2("Group %1 getting in a vehicle %2", _group, _vehicle); +TRACE_2("Group %1 getting in a vehicle %2",_group,_vehicle); diff --git a/addons/common/functions/fnc_getNearestCityLocation.sqf b/addons/common/functions/fnc_getNearestCityLocation.sqf index c7e0e876..00a20494 100644 --- a/addons/common/functions/fnc_getNearestCityLocation.sqf +++ b/addons/common/functions/fnc_getNearestCityLocation.sqf @@ -29,7 +29,7 @@ if (_pos isEqualType objNull) then { private _towns = nearestLocations [_pos, ["NameVillage", "NameCity", "NameCityCapital"], _searchRadius]; #define GET_NEAREST_LOCATION _towns param [0, locationNull] -TRACE_2("Nearest location for pos: %1 is location: %2", _pos, GET_NEAREST_LOCATION); +TRACE_2("Nearest location for pos: %1 is location: %2",_pos,GET_NEAREST_LOCATION); // Select nearest location from array. _towns param [0, locationNull] diff --git a/addons/common/functions/fnc_getNearestLocation.sqf b/addons/common/functions/fnc_getNearestLocation.sqf index d465cba5..a34c520d 100644 --- a/addons/common/functions/fnc_getNearestLocation.sqf +++ b/addons/common/functions/fnc_getNearestLocation.sqf @@ -30,7 +30,7 @@ private _locations = nearestLocations [_pos, GVAR(allLocationTypes), _searchRadi // Introduced so that there are no issues with ',' in TRACE macro. #define GET_NEAREST_LOCATION _locations param [0, locationNull] -TRACE_2("(getNearestLocation) Pos: %1 Location: %2", _pos, GET_NEAREST_LOCATION); +TRACE_2("(getNearestLocation) Pos: %1 Location: %2",_pos,GET_NEAREST_LOCATION); // Select nearest location from array. _locations param [0, locationNull] diff --git a/addons/jail/functions/fnc_addReleaseAction.sqf b/addons/jail/functions/fnc_addReleaseAction.sqf index 0e7c671a..7539e12c 100644 --- a/addons/jail/functions/fnc_addReleaseAction.sqf +++ b/addons/jail/functions/fnc_addReleaseAction.sqf @@ -24,8 +24,8 @@ private _actionID = [ LLSTRING(Release_Prisoner), "", "", - QUOTE([ARR_2(_this, _target)] call FUNC(canRelease)), - QUOTE([ARR_2(_caller, _target)] call FUNC(canRelease)), + QUOTE([ARR_2(_this,_target)] call FUNC(canRelease)), + QUOTE([ARR_2(_caller,_target)] call FUNC(canRelease)), {}, {}, { params ["_target", "_caller", "_actionId", "_arguments"]; diff --git a/addons/police/functions/fnc_equipmentScoreCheck.sqf b/addons/police/functions/fnc_equipmentScoreCheck.sqf index ea34bd16..c656cd6a 100644 --- a/addons/police/functions/fnc_equipmentScoreCheck.sqf +++ b/addons/police/functions/fnc_equipmentScoreCheck.sqf @@ -17,19 +17,19 @@ private _step = if ((EGVAR(score,policeScore) - GVAR(lastEquipmentUpdateScore)) > 0) then {1} else {-1}; -TRACE_3("(equipmentScoreCheck) Performing check from %1 to %2 step %3", GVAR(lastEquipmentUpdateScore), EGVAR(score,policeScore), _step); +TRACE_3("(equipmentScoreCheck) Performing check from %1 to %2 step %3",GVAR(lastEquipmentUpdateScore),EGVAR(score,policeScore),_step); while {GVAR(lastEquipmentUpdateScore) != EGVAR(score,policeScore)} do { if (_step > 0) then { GVAR(lastEquipmentUpdateScore) = GVAR(lastEquipmentUpdateScore) + _step; }; - TRACE_1("(equipmentScoreCheck) Checking %1", GVAR(lastEquipmentUpdateScore)); + TRACE_1("(equipmentScoreCheck) Checking %1",GVAR(lastEquipmentUpdateScore)); private _scoreItems = EGVAR(equipment,policeEquipmentScores) getVariable [str GVAR(lastEquipmentUpdateScore), []]; private _scoreVehicles = EGVAR(equipment,policeVehiclesScores) getVariable [str GVAR(lastEquipmentUpdateScore), []]; - TRACE_2("(equipmentScoreCheck) Found %1 equipment and %2 vehicles", _scoreItems, _scoreVehicles); + TRACE_2("(equipmentScoreCheck) Found %1 equipment and %2 vehicles",_scoreItems,_scoreVehicles); { if (_step > 0) then { From 4bfac13cc58e10dab4aaf2b70185cd48a235af4e Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:50:23 +0100 Subject: [PATCH 05/15] Fix command casing --- .hemtt/lints.toml | 1 + addons/civilian/functions/fnc_assignCityCivilian.sqf | 2 +- addons/civilian/functions/fnc_civilianKilled.sqf | 2 +- addons/civilian/functions/fnc_civilianKilledMsg.sqf | 2 +- addons/equipment/functions/fnc_initPoliceEquipment.sqf | 2 +- .../functions/fnc_createMarkersForNearbyVehicles.sqf | 2 +- .../functions/fnc_createStartPositionMarker.sqf | 10 +++++----- addons/killers/functions/fnc_createStashesMarkers.sqf | 8 ++++---- addons/killers/functions/fnc_initKillersStashes.sqf | 2 +- addons/markers/functions/fnc_loop.sqf | 2 +- addons/missions/XEH_postInit.sqf | 2 +- addons/police/XEH_postInit.sqf | 2 +- addons/police/functions/fnc_copKilled.sqf | 2 +- addons/police/functions/fnc_copKilledMsg.sqf | 2 +- addons/score/functions/fnc_addKillersScore.sqf | 2 +- addons/score/functions/fnc_addPoliceScore.sqf | 2 +- addons/score/functions/fnc_showScore.sqf | 2 +- addons/vehicles/functions/fnc_vehicleStolenMsg.sqf | 2 +- tools/search_unused_privates.py | 8 ++++---- 19 files changed, 29 insertions(+), 28 deletions(-) diff --git a/.hemtt/lints.toml b/.hemtt/lints.toml index a8fd636e..025af8ce 100644 --- a/.hemtt/lints.toml +++ b/.hemtt/lints.toml @@ -1,5 +1,6 @@ [sqf.command_case] options.ignore = [ + "CIVILIAN", "EAST", "WEST", ] diff --git a/addons/civilian/functions/fnc_assignCityCivilian.sqf b/addons/civilian/functions/fnc_assignCityCivilian.sqf index 620cb895..3d69e2b6 100644 --- a/addons/civilian/functions/fnc_assignCityCivilian.sqf +++ b/addons/civilian/functions/fnc_assignCityCivilian.sqf @@ -18,7 +18,7 @@ params ["_civilian", "_cityNamespace"]; -// Get city civilians array and pushback new civilian. No need for setVariable as getVariable returns array pointer. +// Get city civilians array and pushBack new civilian. No need for setVariable as getVariable returns array pointer. _cityCivilians = _cityNamespace getVariable QGVAR(CiviliansList); _cityCivilians pushBack _civilian; _cityNamespace setVariable [QGVAR(CiviliansCount), count _cityCivilians]; diff --git a/addons/civilian/functions/fnc_civilianKilled.sqf b/addons/civilian/functions/fnc_civilianKilled.sqf index e78acade..8fd2cab1 100644 --- a/addons/civilian/functions/fnc_civilianKilled.sqf +++ b/addons/civilian/functions/fnc_civilianKilled.sqf @@ -31,7 +31,7 @@ if (count GVAR(civilians) isEqualTo 0) then { [QEGVAR(score,allCiviliansDead)] call CBA_fnc_serverEvent; }; -private _time = [daytime] call BIS_fnc_timeToString; +private _time = [dayTime] call BIS_fnc_timeToString; // Call function to create marker at killed unit's position. [_civilian, _time] call FUNC(civilianKilledMarker); // Show message for all cops that cop has been killed near some location with timestamp diff --git a/addons/civilian/functions/fnc_civilianKilledMsg.sqf b/addons/civilian/functions/fnc_civilianKilledMsg.sqf index fe1190ed..f4883feb 100644 --- a/addons/civilian/functions/fnc_civilianKilledMsg.sqf +++ b/addons/civilian/functions/fnc_civilianKilledMsg.sqf @@ -18,7 +18,7 @@ * Public: No */ -params ["_unit", ["_killer", objNull], ["_timeOfDeath", daytime], ["_nearestTown", locationNull]]; +params ["_unit", ["_killer", objNull], ["_timeOfDeath", dayTime], ["_nearestTown", locationNull]]; if (_timeOfDeath isEqualType 0) then { _timeOfDeath = [_timeOfDeath] call BIS_fnc_timeToString; diff --git a/addons/equipment/functions/fnc_initPoliceEquipment.sqf b/addons/equipment/functions/fnc_initPoliceEquipment.sqf index bb129c30..bb85374a 100644 --- a/addons/equipment/functions/fnc_initPoliceEquipment.sqf +++ b/addons/equipment/functions/fnc_initPoliceEquipment.sqf @@ -61,7 +61,7 @@ _policeEquipmentList sort true; _itemNamespace = GVAR(commonEquipment) getVariable [_itemClassname, call CBA_fnc_createNamespace]; }; private _loadMagazines = _itemNamespace getVariable ["loadMagazines", true]; - if (_loadMagazines isEqualTo "false") exitwith {}; + if (_loadMagazines isEqualTo "false") exitWith {}; // Get compatible magazines and add them if not added yet private _magazines = [_itemClassName, true] call CBA_fnc_compatibleMagazines; { diff --git a/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf b/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf index 08127911..71a6dbaf 100644 --- a/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf +++ b/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf @@ -36,7 +36,7 @@ private _emptyVehicles = _nearbyVehicles select { _marker setMarkerColorLocal "ColorCIVILIAN"; _marker setMarkerSizeLocal [0.5, 0.5]; _marker setMarkerAlphaLocal 1; // Force just in case marker already exists and should be fully-visible again - _marker setMarkerTextLocal getText (configFile >> "CfgVehicles" >> (typeof _vehicle) >> "displayName"); + _marker setMarkerTextLocal getText (configFile >> "CfgVehicles" >> (typeOf _vehicle) >> "displayName"); private _markerType = if (_vehicle isKindOf "Air") then { if (_vehicle isKindOf "Plane") then { "loc_plane" } else { "loc_heli" } diff --git a/addons/killers/functions/fnc_createStartPositionMarker.sqf b/addons/killers/functions/fnc_createStartPositionMarker.sqf index debde5ff..97288f31 100644 --- a/addons/killers/functions/fnc_createStartPositionMarker.sqf +++ b/addons/killers/functions/fnc_createStartPositionMarker.sqf @@ -22,11 +22,11 @@ if (_name isEqualTo "") then { _name = [_pos] call EFUNC(common,getNearestLocationName); }; -private _marker = createMarkerlocal [_name, _pos]; -_marker setMarkerColorlocal "ColorEAST"; -_marker setMarkerSizelocal [0.5,0.5]; -_marker setMarkerTypelocal "mil_end"; +private _marker = createMarkerLocal [_name, _pos]; +_marker setMarkerColorLocal "ColorEAST"; +_marker setMarkerSizeLocal [0.5,0.5]; +_marker setMarkerTypeLocal "mil_end"; _marker setMarkerTextLocal _name; -GVAR(startPositionsMarkers) pushback _marker; +GVAR(startPositionsMarkers) pushBack _marker; _marker diff --git a/addons/killers/functions/fnc_createStashesMarkers.sqf b/addons/killers/functions/fnc_createStashesMarkers.sqf index ef9cdd3f..d17234aa 100644 --- a/addons/killers/functions/fnc_createStashesMarkers.sqf +++ b/addons/killers/functions/fnc_createStashesMarkers.sqf @@ -16,9 +16,9 @@ */ { - private _marker = createMarkerlocal [str _x, getPosATL _x]; - _marker setMarkerColorlocal "ColorEAST"; - _marker setMarkerSizelocal [0.5,0.5]; - _marker setMarkerTypelocal "mil_pickup"; + private _marker = createMarkerLocal [str _x, getPosATL _x]; + _marker setMarkerColorLocal "ColorEAST"; + _marker setMarkerSizeLocal [0.5,0.5]; + _marker setMarkerTypeLocal "mil_pickup"; _x setVariable [QGVAR(marker), _marker]; } forEach GVAR(stashes); diff --git a/addons/killers/functions/fnc_initKillersStashes.sqf b/addons/killers/functions/fnc_initKillersStashes.sqf index ab07898f..49cd544c 100644 --- a/addons/killers/functions/fnc_initKillersStashes.sqf +++ b/addons/killers/functions/fnc_initKillersStashes.sqf @@ -40,7 +40,7 @@ for "_y" from 0 to (_createStatshesCount - 1) step 1 do { _box setVariable [QGVAR(killersStash), _stash]; _stash setVariable [QGVAR(box), _box]; _box call FUNC(fillKillersStash); - GVAR(stashes) pushback _box; + GVAR(stashes) pushBack _box; }; publicVariable QGVAR(stashes); diff --git a/addons/markers/functions/fnc_loop.sqf b/addons/markers/functions/fnc_loop.sqf index a3e01783..49f226db 100644 --- a/addons/markers/functions/fnc_loop.sqf +++ b/addons/markers/functions/fnc_loop.sqf @@ -31,7 +31,7 @@ }; #endif }; -} foreach EGVAR(civilian,civilians); +} forEach EGVAR(civilian,civilians); // Move marker for every cop if (playerSide isEqualTo WEST) then { diff --git a/addons/missions/XEH_postInit.sqf b/addons/missions/XEH_postInit.sqf index b5205f77..be60e994 100644 --- a/addons/missions/XEH_postInit.sqf +++ b/addons/missions/XEH_postInit.sqf @@ -5,5 +5,5 @@ if (!EGVAR(common,enabled)) exitWith {}; [{alive player}, { private _welcomeText = format [LLSTRING(Welcome_Message), QUOTE(VERSION_STR)]; - titletext [_welcomeText, "plain"]; + titleText [_welcomeText, "plain"]; }] call CBA_fnc_waitUntilAndExecute; diff --git a/addons/police/XEH_postInit.sqf b/addons/police/XEH_postInit.sqf index 19125f0e..823c1e4c 100644 --- a/addons/police/XEH_postInit.sqf +++ b/addons/police/XEH_postInit.sqf @@ -58,7 +58,7 @@ if (isServer) then { [QEGVAR(score,scoreChanged), { params ["_side", "_change", ["_reason", ""]]; - if (_side isEqualTo EAST) exitwith {}; + if (_side isEqualTo EAST) exitWith {}; call FUNC(equipmentScoreCheck); }] call CBA_fnc_addEventHandler; diff --git a/addons/police/functions/fnc_copKilled.sqf b/addons/police/functions/fnc_copKilled.sqf index 612c0463..1c2ae26b 100644 --- a/addons/police/functions/fnc_copKilled.sqf +++ b/addons/police/functions/fnc_copKilled.sqf @@ -20,7 +20,7 @@ params ["_unit", "_killer"]; if !(isServer) exitWith {}; -private _time = [daytime] call BIS_fnc_timeToString; +private _time = [dayTime] call BIS_fnc_timeToString; private _isPlayerOrAi = ["AI", "PLAYER"] select isPlayer _killer; LOG_4("Cop %1 was killed by %2 %3 at %4",name _unit,_isPlayerOrAi,name _killer,_time); diff --git a/addons/police/functions/fnc_copKilledMsg.sqf b/addons/police/functions/fnc_copKilledMsg.sqf index 181c0528..e0f24731 100644 --- a/addons/police/functions/fnc_copKilledMsg.sqf +++ b/addons/police/functions/fnc_copKilledMsg.sqf @@ -17,7 +17,7 @@ * Public: No */ -params ["_unit", "_killer", ["_timeOfDeath", daytime], ["_nearestTown", locationNull]]; +params ["_unit", "_killer", ["_timeOfDeath", dayTime], ["_nearestTown", locationNull]]; if (_timeOfDeath isEqualType 0) then { _timeOfDeath = [_timeOfDeath] call BIS_fnc_timeToString; diff --git a/addons/score/functions/fnc_addKillersScore.sqf b/addons/score/functions/fnc_addKillersScore.sqf index 2dda71f2..3986e0d2 100644 --- a/addons/score/functions/fnc_addKillersScore.sqf +++ b/addons/score/functions/fnc_addKillersScore.sqf @@ -18,7 +18,7 @@ params ["_scoreChange", ["_reason", ""]]; -private _time = [daytime] call BIS_fnc_timeToString; +private _time = [dayTime] call BIS_fnc_timeToString; // Change killers score GVAR(killersScore) = GVAR(killersScore) + _scoreChange; diff --git a/addons/score/functions/fnc_addPoliceScore.sqf b/addons/score/functions/fnc_addPoliceScore.sqf index 4f5ad516..d551778c 100644 --- a/addons/score/functions/fnc_addPoliceScore.sqf +++ b/addons/score/functions/fnc_addPoliceScore.sqf @@ -18,7 +18,7 @@ params ["_scoreChange", ["_reason", ""]]; -private _time = [daytime] call BIS_fnc_timeToString; +private _time = [dayTime] call BIS_fnc_timeToString; // Change police score GVAR(policeScore) = GVAR(policeScore) + _scoreChange; diff --git a/addons/score/functions/fnc_showScore.sqf b/addons/score/functions/fnc_showScore.sqf index 74c362c9..52131c81 100644 --- a/addons/score/functions/fnc_showScore.sqf +++ b/addons/score/functions/fnc_showScore.sqf @@ -30,7 +30,7 @@ private _fnc_determineSign = { private _separator = parseText "
---------------------------
"; _separator setAttributes ["align", "center"]; -private _msgHour = text format ["%1", [daytime] call BIS_fnc_timeToString]; +private _msgHour = text format ["%1", [dayTime] call BIS_fnc_timeToString]; _msgHour setAttributes ["align", "center"]; private _msgKillers = text format ["%1", LELSTRING(killers,Killers)]; diff --git a/addons/vehicles/functions/fnc_vehicleStolenMsg.sqf b/addons/vehicles/functions/fnc_vehicleStolenMsg.sqf index 221b5fba..6599db3a 100644 --- a/addons/vehicles/functions/fnc_vehicleStolenMsg.sqf +++ b/addons/vehicles/functions/fnc_vehicleStolenMsg.sqf @@ -17,7 +17,7 @@ * Public: No */ -params ["_stolenVehicle", ["_timeOfTheft", daytime], ["_nearestTown", locationNull]]; +params ["_stolenVehicle", ["_timeOfTheft", dayTime], ["_nearestTown", locationNull]]; if (_timeOfTheft isEqualType 0) then { _timeOfTheft = [_timeOfTheft] call BIS_fnc_timeToString; diff --git a/tools/search_unused_privates.py b/tools/search_unused_privates.py index d62db28e..6550178a 100644 --- a/tools/search_unused_privates.py +++ b/tools/search_unused_privates.py @@ -67,10 +67,10 @@ def popClosing(): if '_forEachIndex' in priv_declared: priv_declared.remove('_forEachIndex') if '_forEachIndex' in priv_use: priv_use.remove('_forEachIndex') - if '_foreachIndex' in priv_declared: priv_declared.remove('_foreachIndex') - if '_foreachIndex' in priv_use: priv_use.remove('_foreachIndex') - if '_foreachindex' in priv_declared: priv_declared.remove('_foreachindex') - if '_foreachindex' in priv_use: priv_use.remove('_foreachindex') + if '_forEachIndex' in priv_declared: priv_declared.remove('_forEachIndex') + if '_forEachIndex' in priv_use: priv_use.remove('_forEachIndex') + if '_forEachindex' in priv_declared: priv_declared.remove('_forEachindex') + if '_forEachindex' in priv_use: priv_use.remove('_forEachindex') unused = [] for s in priv_declared: From 4c52f82c80ddbf57a17ef7bc2654ff34ebceff59 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:54:14 +0100 Subject: [PATCH 06/15] Use select instead of if --- addons/common/XEH_postInit.sqf | 2 +- addons/common/functions/fnc_isHouseNearby.sqf | 7 ++----- addons/common/functions/fnc_isRoadNearby.sqf | 7 ++----- .../functions/fnc_getRequiredScoreForItem.sqf | 6 +----- .../functions/fnc_createMarkersForNearbyVehicles.sqf | 2 +- addons/score/functions/fnc_endMissionClient.sqf | 10 +++++----- addons/vehicles/functions/fnc_carAlarmNotification.sqf | 2 +- addons/vehicles/functions/fnc_createVehicle.sqf | 2 +- 8 files changed, 14 insertions(+), 24 deletions(-) diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 0dbe45aa..255dd5d1 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -22,7 +22,7 @@ if (isServer) then { [QGVAR(showSideChatMsg), { params [["_side", sideEmpty], ["_msg", ""]]; if (_msg isEqualTo "") exitWith {}; - private _sideText = if (_side isEqualTo sideEmpty) then { "ALL" } else { _side }; + private _sideText = [_side, "ALL"] select (_side isEqualTo sideEmpty); INFO_2("(Side Chat) %1: %2",_sideText,_msg call BIS_fnc_localize); }] call CBA_fnc_addEventHandler; }; diff --git a/addons/common/functions/fnc_isHouseNearby.sqf b/addons/common/functions/fnc_isHouseNearby.sqf index e68e6f8e..6a79ed28 100644 --- a/addons/common/functions/fnc_isHouseNearby.sqf +++ b/addons/common/functions/fnc_isHouseNearby.sqf @@ -18,8 +18,5 @@ params ["_position"]; private _houses = nearestTerrainObjects [_position, ["House"], 50, false]; -if (_houses isEqualTo []) then { - false -} else { - true -}; + +[true, false] select (_houses isEqualTo []) diff --git a/addons/common/functions/fnc_isRoadNearby.sqf b/addons/common/functions/fnc_isRoadNearby.sqf index 436b7f23..05f0ff01 100644 --- a/addons/common/functions/fnc_isRoadNearby.sqf +++ b/addons/common/functions/fnc_isRoadNearby.sqf @@ -18,8 +18,5 @@ params ["_position"]; private _roads = _position nearRoads 50; -if (_roads isEqualTo []) then { - false -} else { - true -}; + +[true, false] select (_roads isEqualTo []) diff --git a/addons/equipment/functions/fnc_getRequiredScoreForItem.sqf b/addons/equipment/functions/fnc_getRequiredScoreForItem.sqf index 65a1e72b..becda7ff 100644 --- a/addons/equipment/functions/fnc_getRequiredScoreForItem.sqf +++ b/addons/equipment/functions/fnc_getRequiredScoreForItem.sqf @@ -26,11 +26,7 @@ if (_item isEqualType objNull) then { if (_item isEqualTo "") exitWith {-1}; // Check if given item is a vehicle -private _namespace = if (isClass (configFile >> "CfgVehicles" >> _item)) then { - GVAR(policeVehiclesScores) -} else { - GVAR(policeEquipmentScores) -}; +private _namespace = [GVAR(policeEquipmentScores), GVAR(policeVehiclesScores)] select isClass (configFile >> "CfgVehicles" >> _item); // Lowercase search only _item = toLower _item; diff --git a/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf b/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf index 71a6dbaf..b3719cbf 100644 --- a/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf +++ b/addons/killers/functions/fnc_createMarkersForNearbyVehicles.sqf @@ -39,7 +39,7 @@ private _emptyVehicles = _nearbyVehicles select { _marker setMarkerTextLocal getText (configFile >> "CfgVehicles" >> (typeOf _vehicle) >> "displayName"); private _markerType = if (_vehicle isKindOf "Air") then { - if (_vehicle isKindOf "Plane") then { "loc_plane" } else { "loc_heli" } + ["loc_heli", "loc_plane"] select (_vehicle isKindOf "Plane") } else { "loc_car" }; _marker setMarkerTypeLocal _markerType; diff --git a/addons/score/functions/fnc_endMissionClient.sqf b/addons/score/functions/fnc_endMissionClient.sqf index 41d0d9d6..b36ccbb7 100644 --- a/addons/score/functions/fnc_endMissionClient.sqf +++ b/addons/score/functions/fnc_endMissionClient.sqf @@ -24,27 +24,27 @@ GVAR(missionEnd) = _endType; switch (_endType) do { // 0 case KILLERS_SCORE_REACHED: { - private _win = if (playerSide isEqualTo EAST) then {true} else {false}; + private _win = [false, true] select (playerSide isEqualTo EAST); [QGVAR(killersScoreReached), _win, nil, false] call BIS_fnc_endMission; }; // 1 case KILLERS_DEAD: { - private _win = if (playerSide isEqualTo WEST) then {true} else {false}; + private _win = [false, true] select (playerSide isEqualTo WEST); [QGVAR(killersDead), _win, nil, false] call BIS_fnc_endMission; }; // 2 case MAXIMUM_TIMEOUT_REACHED: { - private _win = if (playerSide isEqualTo WEST) then {true} else {false}; + private _win = [false, true] select (playerSide isEqualTo WEST); [QGVAR(timeoutLimit), _win, nil, false] call BIS_fnc_endMission; }; // 3 case TIME_LIMIT_REACHED: { - private _win = if (playerSide isEqualTo WEST) then {true} else {false}; + private _win = [false, true] select (playerSide isEqualTo WEST); [QGVAR(timeLimit), _win, nil, false] call BIS_fnc_endMission; }; // 4 case ALL_CIVILIANS_DEAD: { - private _win = if (playerSide isEqualTo EAST) then {true} else {false}; + private _win = [false, true] select (playerSide isEqualTo EAST); [QGVAR(civiliansDead), _win, nil, false] call BIS_fnc_endMission; }; default { diff --git a/addons/vehicles/functions/fnc_carAlarmNotification.sqf b/addons/vehicles/functions/fnc_carAlarmNotification.sqf index 3a2e06ad..f9c93bdf 100644 --- a/addons/vehicles/functions/fnc_carAlarmNotification.sqf +++ b/addons/vehicles/functions/fnc_carAlarmNotification.sqf @@ -31,7 +31,7 @@ private _notify = if (GVAR(alarmCopsNotification) isEqualTo 1) then { private _anyNearbyUnrestrainedCivilians = _nearbyUnits findIf {alive _x && {side _x isEqualTo CIVILIAN && {!([_x] call EFUNC(jail,isHandcuffed))}}} != -1; - if (_anyNearbyUnrestrainedCivilians) then { true } else { false }; + [false, true] select (_anyNearbyUnrestrainedCivilians) }; if (_notify) exitWith { diff --git a/addons/vehicles/functions/fnc_createVehicle.sqf b/addons/vehicles/functions/fnc_createVehicle.sqf index 7b0c94dd..edb6b70c 100644 --- a/addons/vehicles/functions/fnc_createVehicle.sqf +++ b/addons/vehicles/functions/fnc_createVehicle.sqf @@ -28,7 +28,7 @@ if (_position isEqualType objNull) then { _position = getPosATL _position; }; -private _mode = if (_forcePosition) then {"CAN_COLLIDE"} else {"NONE"}; +private _mode = ["NONE", "CAN_COLLIDE"] select (_forcePosition); private _vehicle = createVehicle [_vehicleClassname, _position, [], 0, _mode]; _vehicle setDir _dir; // Disable randomization and use own function to set texture on vehicle globally (so everyone can see the same color!) From 454c21519bb3ff5a92fa88ee43ddfb8bc979c429 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:54:44 +0100 Subject: [PATCH 07/15] Remove repeated calls to global marker --- addons/jail/functions/fnc_jailMarker.sqf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/jail/functions/fnc_jailMarker.sqf b/addons/jail/functions/fnc_jailMarker.sqf index 13835a29..b675fb0f 100644 --- a/addons/jail/functions/fnc_jailMarker.sqf +++ b/addons/jail/functions/fnc_jailMarker.sqf @@ -17,8 +17,8 @@ private _markerText = format ["%1", LLSTRING(Jail)]; private _marker = createMarker ["jail", getPosATL GVAR(jail)]; -_marker setMarkerType "mil_end"; -_marker setMarkerColor "ColorEAST"; +_marker setMarkerTypeLocal "mil_end"; +_marker setMarkerColorLocal "ColorEAST"; _marker setMarkerText _markerText; _marker From cae600f6daaa30caf541202ebfce44895861f5fc Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 16:55:23 +0100 Subject: [PATCH 08/15] Sort stringtables --- addons/briefing/stringtable.xml | 8 +- addons/civilian/stringtable.xml | 162 ++++++++-------- addons/equipment/stringtable.xml | 14 +- addons/jail/stringtable.xml | 8 +- addons/modules/stringtable.xml | 8 +- addons/police/stringtable.xml | 46 ++--- addons/score/stringtable.xml | 318 +++++++++++++++---------------- addons/vehicles/stringtable.xml | 94 ++++----- 8 files changed, 329 insertions(+), 329 deletions(-) diff --git a/addons/briefing/stringtable.xml b/addons/briefing/stringtable.xml index fd229ee5..3e08f35d 100644 --- a/addons/briefing/stringtable.xml +++ b/addons/briefing/stringtable.xml @@ -5,6 +5,10 @@ SerialKillers - Briefing SerialKillers - Odprawa + + Rules + Zasady + Enable rules Włącz zasady @@ -13,10 +17,6 @@ If enabled, suggested rules will be visible on the map in "SerialKillers" briefing section. Jeżeli włączone, proponowane zasady będą widoczne na odprawnie na mapie w zakładce "SerialKillers". - - Rules - Zasady - Cops are not allowed to use terrorist stashes/weapons. They may only use radios they find after neutralizing a terrorist. Policjanci nie mogą używać broni terrorystów ani skrytek z bronią. Mogą używać jedynie radia, które znajdą przy zneutralizowanym terroryście. diff --git a/addons/civilian/stringtable.xml b/addons/civilian/stringtable.xml index 7a922de1..a38217be 100644 --- a/addons/civilian/stringtable.xml +++ b/addons/civilian/stringtable.xml @@ -1,74 +1,6 @@ - - SerialKillers - Civilian - SerialKillers - Cywile - - - Civilian vehicles limit - Limit pojazdów cywilnych - - - Controls how much civilian vehicles will be created on the whole map. - Ustala jak dużo pojazdów cywilnych będzie utworzonych na całej mapie. - - - Civilian was killed at %1 in %2! - Cywil został zabity o godzinie %1 w %2! - - - Civilian was killed at %1 near %2! - Cywil został zabity o godzinie %1 w pobliżu %2! - - - Civilian was killed by cop %3 at %1 in %2! - Cywil został zabity przez policjanta %3 o godzinie %1 w %2! - - - Civilian was killed by cop %3 at %1 near %2! - Cywil został zabity przez policjanta %3 o godzinie %1 w pobliżu %2! - - - Civilians count - Liczba cywili - - - Number of generated civilians on mission startup. Final number will be in +-10% range. Set 0 to randomize between 100-200. - Liczba generowanych cywili na starcie misji. Właściwa liczba będzie z przedziału +-10%. Losowana z przedziału 100-200 gdy ustawienie jest równe 0. - - - Guaranteed civilian in every location - Gwarantowany cywil w każdej lokacji - - - If checked, every village, city and capital will have at least 1 civilian on start (if limit allows). - Jeżeli zaznaczone, każda wioska, miasto i stolica będą miały przynajmniej 1 cywila na start (jeżeli pozwoli na to limit). - - - Location area - Obszar lokacji - - - Respect city area - Respektuj obszar miasta - - - Village civilians weight multiplier - Mnożnik cywili w wioskach - - - Weight multiplier for villages when civilians are spawned. The higher (relatively to other location types), the more civilians (on average) will be in villages on the same area. - Mnożnik wagi dla wiosek podczas spawnowania cywili. Im wyższy (w stosunku do innych typów lokacji), tym średnio więcej cywili będzie wygenerowanych w wioskach na tym samym obszarze. - - - City civilians weight multiplier - Mnożnik cywili w miastach - - - Weight multiplier for cities when civilians are spawned. The higher (relatively to other location types), the more civilians (on average) will be in cities on the same area. - Mnożnik wagi dla miast podczas spawnowania cywili. Im wyższy (w stosunku do innych typów lokacji), tym średnio więcej cywili będzie wygenerowanych w miastach o samym obszarze. - Capital civilians weight multiplier Mnożnik cywili w stolicy @@ -77,17 +9,13 @@ Weight multiplier for capital(s) when civilians are spawned. The higher (relatively to other location types), the more civilians (on average) will be in capital(s) on the same area. Mnożnik wagi dla stolic podczas spawnowania cywili. Im wyższy (w stosunku do innych typów lokacji), tym średnio więcej cywili będzie wygenerowanych w stolicach na tym samym obszarze. - - Civilians will be spawned in cities area as defined in map location configuration. Otherwise, values below will be used to define area for each location type. - Cywile będą spawnowani w miastach o obszarze zdefiniowanym w konfiguracji lokacji mapy. W przeciwnym razie wartości wyszczególnione poniżej zostaną użyte do zdefiniowania rozmiaru każdej lokacji. - - - Custom village area radius - Własny promień obszaru wioski + + City civilians weight multiplier + Mnożnik cywili w miastach - - When map locations are badly defined, this can be used to control how large villages are on a given map. This is used for spawning civilians, waypoints and some other things. - Gdy lokacje na mapie są słabo zdefiniowane, można ustawić ręcznie jak duże są wioski na danej mapie. Jest to używane do spawnownia cywili, waypointów i wielu innych rzeczy. + + Weight multiplier for cities when civilians are spawned. The higher (relatively to other location types), the more civilians (on average) will be in cities on the same area. + Mnożnik wagi dla miast podczas spawnowania cywili. Im wyższy (w stosunku do innych typów lokacji), tym średnio więcej cywili będzie wygenerowanych w miastach o samym obszarze. Custom city area radius @@ -105,6 +33,46 @@ When map locations are badly defined, this can be used to control how large capital(s) are on a given map. This is used for spawning civilians, waypoints and some other things. Gdy lokacje na mapie są słabo zdefiniowane, można ustawić ręcznie jak duże są stolice na danej mapie. Jest to używane do spawnownia cywili, waypointów i wielu innych rzeczy. + + Custom village area radius + Własny promień obszaru wioski + + + When map locations are badly defined, this can be used to control how large villages are on a given map. This is used for spawning civilians, waypoints and some other things. + Gdy lokacje na mapie są słabo zdefiniowane, można ustawić ręcznie jak duże są wioski na danej mapie. Jest to używane do spawnownia cywili, waypointów i wielu innych rzeczy. + + + SerialKillers - Civilian + SerialKillers - Cywile + + + Civilian vehicles limit + Limit pojazdów cywilnych + + + Controls how much civilian vehicles will be created on the whole map. + Ustala jak dużo pojazdów cywilnych będzie utworzonych na całej mapie. + + + Guaranteed civilian in every location + Gwarantowany cywil w każdej lokacji + + + If checked, every village, city and capital will have at least 1 civilian on start (if limit allows). + Jeżeli zaznaczone, każda wioska, miasto i stolica będą miały przynajmniej 1 cywila na start (jeżeli pozwoli na to limit). + + + High + Dużo + + + Civilians count + Liczba cywili + + + Number of generated civilians on mission startup. Final number will be in +-10% range. Set 0 to randomize between 100-200. + Liczba generowanych cywili na starcie misji. Właściwa liczba będzie z przedziału +-10%. Losowana z przedziału 100-200 gdy ustawienie jest równe 0. + Civilian was killed Cywil został zabity @@ -113,6 +81,26 @@ Civilian was killed by cop Cywil został zabity przez policjanta + + Civilian was killed by cop %3 at %1 in %2! + Cywil został zabity przez policjanta %3 o godzinie %1 w %2! + + + Civilian was killed by cop %3 at %1 near %2! + Cywil został zabity przez policjanta %3 o godzinie %1 w pobliżu %2! + + + Civilian was killed at %1 in %2! + Cywil został zabity o godzinie %1 w %2! + + + Civilian was killed at %1 near %2! + Cywil został zabity o godzinie %1 w pobliżu %2! + + + Location area + Obszar lokacji + Low Mało @@ -121,9 +109,21 @@ Mediun Średnio - - High - Dużo + + Respect city area + Respektuj obszar miasta + + + Civilians will be spawned in cities area as defined in map location configuration. Otherwise, values below will be used to define area for each location type. + Cywile będą spawnowani w miastach o obszarze zdefiniowanym w konfiguracji lokacji mapy. W przeciwnym razie wartości wyszczególnione poniżej zostaną użyte do zdefiniowania rozmiaru każdej lokacji. + + + Village civilians weight multiplier + Mnożnik cywili w wioskach + + + Weight multiplier for villages when civilians are spawned. The higher (relatively to other location types), the more civilians (on average) will be in villages on the same area. + Mnożnik wagi dla wiosek podczas spawnowania cywili. Im wyższy (w stosunku do innych typów lokacji), tym średnio więcej cywili będzie wygenerowanych w wioskach na tym samym obszarze. diff --git a/addons/equipment/stringtable.xml b/addons/equipment/stringtable.xml index d32c8885..c5cc32e0 100644 --- a/addons/equipment/stringtable.xml +++ b/addons/equipment/stringtable.xml @@ -5,6 +5,10 @@ SerialKillers - Equipment SerialKillers - Ekwipunek + + Predefined equipment preset + Predefiniowana konfiguracja ekwipunku + Custom equipment preset Własna konfiguracja ekwipunku @@ -13,17 +17,13 @@ Use "Custom" equipment preset from mission config. Overwrites predefined mod presets. Użyj konfiguracji "Custom" z pliku konfiguracyjnego w misji. Zastępuje predefiniowane konfiguracje z moda. - - Predefined equipment preset - Predefiniowana konfiguracja ekwipunku + + Automatic preset selection + Automatyczny wybór konfiguracji Use predefined equipment preset from mod config. Użyj predefiniowanej konfiguracji ekwipunku z moda. - - Automatic preset selection - Automatyczny wybór konfiguracji - diff --git a/addons/jail/stringtable.xml b/addons/jail/stringtable.xml index caa7aa43..1fed62dd 100644 --- a/addons/jail/stringtable.xml +++ b/addons/jail/stringtable.xml @@ -9,13 +9,13 @@ Jail Więzienie - - Release prisoner - Uwolnij więźnia - Prisoners have been released from the prison! Więźniowie zostali uwolnieni z więzienia! + + Release prisoner + Uwolnij więźnia + diff --git a/addons/modules/stringtable.xml b/addons/modules/stringtable.xml index c2b530ce..2ca2c5f8 100644 --- a/addons/modules/stringtable.xml +++ b/addons/modules/stringtable.xml @@ -25,13 +25,13 @@ Location Name. If empty will use nearest map location name according to player language. If not empty, the same name will be used for all languages (unless it's stringtable empty starting with $). Nazwa lokacji. Jeżeli puste to użyta zostanie nazwa najbliższej lokacji na mapie zgodnie z językiem gracza. Jeżeli nie będzie puste, ta sama nazwa pokaże się we wszystkich językach (chyba że będzie zawierać wpis lokalizowalny rozpoczynający się od $). - - Police Station - Posterunek Policji - Has helipad Posiada lądowisko dla helikoptera + + Police Station + Posterunek Policji + diff --git a/addons/police/stringtable.xml b/addons/police/stringtable.xml index 509a8474..d7788397 100644 --- a/addons/police/stringtable.xml +++ b/addons/police/stringtable.xml @@ -1,14 +1,6 @@ - - SerialKillers - Police - SerialKillers - Policja - - - Police - Policja - Someone is in %1 police station! Ktoś majstruje coś w bazie policji w %1! @@ -17,13 +9,21 @@ It was a bad idea... To był zły pomysł... - - Cop was killed at %1 in %2! - Policjant został zabity o godzinie %1 w %2! + + SerialKillers - Police + SerialKillers - Policja - - Cop was killed at %1 near %2! - Policjant został zabity o godzinie %1 w pobliżu %2! + + Cannot create %1 at %2. + Nie można utworzyć %1 w %2. + + + Cop was killed + Policjant został zabity + + + Cop was killed by cop + Policjant został zabity przez policjanta Cop was killed by cop %3 at %1 in %2! @@ -33,17 +33,17 @@ Cop was killed by cop %3 at %1 near %2! Policjant został zabity przez policjanta %3 o godzinie %1 w pobliżu %2! - - Cop was killed - Policjant został zabity + + Cop was killed at %1 in %2! + Policjant został zabity o godzinie %1 w %2! - - Cop was killed by cop - Policjant został zabity przez policjanta + + Cop was killed at %1 near %2! + Policjant został zabity o godzinie %1 w pobliżu %2! - - Cannot create %1 at %2. - Nie można utworzyć %1 w %2. + + Police + Policja Save equipment for respawn diff --git a/addons/score/stringtable.xml b/addons/score/stringtable.xml index a0cb28db..5d9916fe 100644 --- a/addons/score/stringtable.xml +++ b/addons/score/stringtable.xml @@ -1,17 +1,134 @@ + + All civilians are dead + Wszyscy cywile nie żyją + + + Killers score when cop is killed + Wynik zabójców gdy policjant zostanie zabity + + + When cop is killed by police killers get this many points. + Zabójcy dostają tyle punktów gdy policjant zginie z rąk policji. + + + Police score for kiling cop + Wynik policji za zabicie policjanta + + + Police get this many points when they kill cop. + Policja dostaje tyle punktów gdy zabije policjanta. + SerialKillers - Score SerialKillers - Wynik - - Killers score target - Maksymalny wynik zabójców + + + Extra time + Dogrywka - - When killers reach given score, they win. - Zabójcy wygrywają, gdy osiągną wskazany wynik. + + Maximum extra time duration + Maksymalna długość dogrywki + + + After this additional time mission instantly ends with police victory. Set to -1 to disable. + Po tym dodatkowym czasie misja kończy się Natychmiastowym zwycięstwem policji. Ustaw na -1 by wyłączyć. + + + Killers score change during extra time + Zmiana wyniku zabójców po przekroczeniu limitu czasu w dogrywce + + + Killers get this many points on timeout during extra time. + Po upłynięciu maksymalnego czasu pomiędzy zabójstwami podczas dogrywki policja dostanie tyle punktów. + + + Police score change during extra time + Zmiana wyniku policji po przekroczeniu limitu czasu w dogrywce + + + Police gets this many points on timeout during extra time. + Po upłynięciu maksymalnego czasu pomiędzy zabójstwami podczas dogrywki policja dostanie tyle punktów. + + + Maximum timeout is adjusted to this value. + Maksymalny odstęp czasu między zabójstwami zostaje zmieniony do tej wartości. + + + Maximum number of timeouts is adjusted to this value. + Maksymalna liczba przekroczeń limitu czasu zostaje zmieniona do tej wartości. + + + Extra time has started + Rozpoczęła się dogrywka + + + + Timeout between kills + Odstęp czasu pomiędzy zabójstwami + + + Allowed idle time: %1 s + Dozwolony czas bezczynności: %1 s + + + Killers score change + Zmiana wyniku zabójców po przekroczeniu limitu czasu + + + Killers get this many points on timeout. + Po upłynięciu maksymalnego czasu pomiędzy zabójstwami policja dostanie tyle punktów. + + + Maximum time between kills (s) + Maksymalny odstęp czasu pomiędzy zabójstwami + + + Maximum idle times: %1 + Maksymalnie %1 razy bezczynności + + + When this time elapses police and killers can have their points adjusted. (-1 to disable) + Po upłynięciu tego czasu policja i zabójcy mogą mieć dodane/odjęte punkty. (-1 by wyłączyć) + + + Police score change + Zmiana wyniku policji po przekroczeniu limitu czasu + + + Police gets this many points on timeout. + Po upłynięciu maksymalnego czasu pomiędzy zabójstwami policja dostanie tyle punktów. + + + Score changes on idle time + Zmiany wyniku po bezczynności + + + + From now on killers must keep killing within %1 minutes since last kill or they will face penalty. + Od tego momentu zabójcy muszą zabić w ciągu %1 minut od ostatniego zabójstwa albo otrzymają karę. + + + Maximum idle time reached %1/%2 + Maksymalny odstęp czasu pomiędzy zabójstwami przekroczony %1/%2 + + + Maximum number of timeouts + Maksymalna liczba przekroczeń limitu czasu + + + Killers lose if then exceed maximum idle time this many times. (-1 to disable) + Zabójcy przegrywają jeśli tyle razy przekroczą limit czasu pomiędzy zabójstwami. (-1 by wyłączyć) @@ -67,64 +168,21 @@ When cop is killed by killers police get this many points. Policja dostaje tyle punktów gdy policjant zginie z rąk zabójców. - - Killers score when cop is killed - Wynik zabójców gdy policjant zostanie zabity - - - When cop is killed by police killers get this many points. - Zabójcy dostają tyle punktów gdy policjant zginie z rąk policji. - - - Police score for kiling cop - Wynik policji za zabicie policjanta - - - Police get this many points when they kill cop. - Policja dostaje tyle punktów gdy zabije policjanta. - - - Score - Wynik - - - - Timeout between kills - Odstęp czasu pomiędzy zabójstwami - - - Maximum number of timeouts - Maksymalna liczba przekroczeń limitu czasu - - - Killers lose if then exceed maximum idle time this many times. (-1 to disable) - Zabójcy przegrywają jeśli tyle razy przekroczą limit czasu pomiędzy zabójstwami. (-1 by wyłączyć) - - - Maximum time between kills (s) - Maksymalny odstęp czasu pomiędzy zabójstwami - - - When this time elapses police and killers can have their points adjusted. (-1 to disable) - Po upłynięciu tego czasu policja i zabójcy mogą mieć dodane/odjęte punkty. (-1 by wyłączyć) - - - Police score change - Zmiana wyniku policji po przekroczeniu limitu czasu + + Killers score target + Maksymalny wynik zabójców - - Police gets this many points on timeout. - Po upłynięciu maksymalnego czasu pomiędzy zabójstwami policja dostanie tyle punktów. + + When killers reach given score, they win. + Zabójcy wygrywają, gdy osiągną wskazany wynik. - - Killers score change - Zmiana wyniku zabójców po przekroczeniu limitu czasu + + All killers are either dead or in custody. + Wszyscy zabójcy są martwi albo w więzieniu. - - Killers get this many points on timeout. - Po upłynięciu maksymalnego czasu pomiędzy zabójstwami policja dostanie tyle punktów. + + Score limit reached + Osiągnięty limit wyniku - - Extra time - Dogrywka - - - Maximum extra time duration - Maksymalna długość dogrywki - - - After this additional time mission instantly ends with police victory. Set to -1 to disable. - Po tym dodatkowym czasie misja kończy się Natychmiastowym zwycięstwem policji. Ustaw na -1 by wyłączyć. - - - Maximum timeout is adjusted to this value. - Maksymalny odstęp czasu między zabójstwami zostaje zmieniony do tej wartości. - - - Maximum number of timeouts is adjusted to this value. - Maksymalna liczba przekroczeń limitu czasu zostaje zmieniona do tej wartości. - - - Police score change during extra time - Zmiana wyniku policji po przekroczeniu limitu czasu w dogrywce - - - Police gets this many points on timeout during extra time. - Po upłynięciu maksymalnego czasu pomiędzy zabójstwami podczas dogrywki policja dostanie tyle punktów. - - - Killers score change during extra time - Zmiana wyniku zabójców po przekroczeniu limitu czasu w dogrywce - - - Killers get this many points on timeout during extra time. - Po upłynięciu maksymalnego czasu pomiędzy zabójstwami podczas dogrywki policja dostanie tyle punktów. - - - - From now on killers must keep killing within %1 minutes since last kill or they will face penalty. - Od tego momentu zabójcy muszą zabić w ciągu %1 minut od ostatniego zabójstwa albo otrzymają karę. - - - Maximum idle time reached %1/%2 - Maksymalny odstęp czasu pomiędzy zabójstwami przekroczony %1/%2 - - - Extra time has started - Rozpoczęła się dogrywka + + Mission time limit reached + Osiągnięty limit czasu misji Remaining time left: %1 min Pozostały czas: %1 min - - Allowed idle time: %1 s - Dozwolony czas bezczynności: %1 s - - - Maximum idle times: %1 - Maksymalnie %1 razy bezczynności - - - Score changes on idle time - Zmiany wyniku po bezczynności + + Timeouts limit reached + Osiągnięty limit przekroczeń limitu czasu diff --git a/addons/vehicles/stringtable.xml b/addons/vehicles/stringtable.xml index 92bfe611..32e177d4 100644 --- a/addons/vehicles/stringtable.xml +++ b/addons/vehicles/stringtable.xml @@ -1,18 +1,6 @@ - - SerialKillers - Vehicles - SerialKillers - Pojazdy - - - Alarm enabled - Alarmy włączone - - - Add car alarms to civilian vehicles. - Dodaj alarmy do pojazdów cywilnych. - Alarm always armed Alarm zawsze uzbrojony @@ -29,14 +17,18 @@ Control exact distance (in meters) at which an alarm can be heard. Increasing the distance makes it easier for cops to spot a stolen vehicle. Kontroluje dokładną odległość (w metrach), z której alarm będzie słyszalny. Zwiększenie tej odległości ułatwia policji zlokalizowanie skradzionego pojazdu. + + Alarm Average Chance + Średnia szansa na alarm + + + Controls the chance of an alarm going off in a car that has the alarm armed. Normal distribution of [min, mid, max]. + Ustala szansę na uruchomienie alarmu w pojeździe posiadającym alarm. Rozkład normalny [minimum, średnia, maksimum]. + Notify cops of alarm Powiadomienie dla policji o alarmie - - When should the cops be notified that an alarm went off? - Kiedy policja powinna być informowana o włączonym alarmie? - Cops notification delay Opóźnienie powiadomienia dla policji @@ -45,6 +37,10 @@ Delay between an alarm going off and possible notification for cops. Opóźnienie pomiędzy włączeniem alarmu a możliwym powiadomieniem dla Policji. + + When should the cops be notified that an alarm went off? + Kiedy policja powinna być informowana o włączonym alarmie? + Alarm disarm if didn't go off Rozbrój alarm jeżeli się nie włączył @@ -53,9 +49,21 @@ Disarm alarm if it didn't go off when a player entered vehicle. Effective only if 'Alarm always armed' is disabled and 'Alarm Minimum Chance' is set to less than 1. Rozbrój alarm jeżeli się nie włączył gdy gracz wszedł do pojazdu. Działa tylko jeżeli ustawienie 'Alarm zawsze uzbrojony' jest wyłączone oraz 'Minimalna szansa na alarm' jest ustawiona na mniej niż 1. - - Alarm Average Chance - Średnia szansa na alarm + + Alarm Duration + Długość alarmu + + + Controls how long will the alarm sound be heard. + Ustala jak długo będzie wył alarm. + + + Alarm enabled + Alarmy włączone + + + Add car alarms to civilian vehicles. + Dodaj alarmy do pojazdów cywilnych. Alarm Maximum Chance @@ -65,22 +73,18 @@ Alarm Minimum Chance Minimalna szansa na alarm - - Controls the chance of an alarm going off in a car that has the alarm armed. Normal distribution of [min, mid, max]. - Ustala szansę na uruchomienie alarmu w pojeździe posiadającym alarm. Rozkład normalny [minimum, średnia, maksimum]. - - - Alarm Duration - Długość alarmu - - - Controls how long will the alarm sound be heard. - Ustala jak długo będzie wył alarm. + + Always + Zawsze Car alarm Alarm samochodowy + + SerialKillers - Vehicles + SerialKillers - Pojazdy + Civilian vehicles limit Limit pojazdów cywilnych @@ -89,13 +93,13 @@ Controls how much civilian vehicles will be created on the whole map. Ustala jak dużo pojazdów cywilnych będzie utworzonych na całej mapie. - - Vehicle was stolen at %1 in %2! - Pojazd został skradziony o godzinie %1 w %2! + + High + Dużo - - Vehicle was stolen at %1 near %2! - Pojazd został skradziony o godzinie %1 w pobliżu %2! + + If civilians nearby + Jeżeli są cywile w pobliżu Low @@ -105,21 +109,17 @@ Mediun Średnio - - High - Dużo - - - Always - Zawsze - Never Nigdy - - If civilians nearby - Jeżeli są cywile w pobliżu + + Vehicle was stolen at %1 in %2! + Pojazd został skradziony o godzinie %1 w %2! + + + Vehicle was stolen at %1 near %2! + Pojazd został skradziony o godzinie %1 w pobliżu %2! From 1c0f1d2b3115d1d7121f62142d9c831786830417 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:00:37 +0100 Subject: [PATCH 09/15] Add (not exactly) missing semicolon --- addons/police/functions/fnc_spawnVehicle.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/police/functions/fnc_spawnVehicle.sqf b/addons/police/functions/fnc_spawnVehicle.sqf index 9689337f..e3c3b3e7 100644 --- a/addons/police/functions/fnc_spawnVehicle.sqf +++ b/addons/police/functions/fnc_spawnVehicle.sqf @@ -45,7 +45,7 @@ if (_emptySpawnPointIndex isEqualTo -1) exitWith { private _fullSpawnPointsWithoutCrew = _spawnPoints select { private _nearEntities = getPosATL _x nearEntities SPAWNPOINT_SAFEZONE; if (_nearEntities isEqualTo []) exitWith { false }; - _nearEntities findIf {crew _x isEqualTo []} isNotEqualTo -1 + _nearEntities findIf {crew _x isEqualTo []} isNotEqualTo -1; }; if (_fullSpawnPointsWithoutCrew isEqualTo []) exitWith { From 77cef995c57002fdcd6db3b5b768fe32884200e6 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:07:54 +0100 Subject: [PATCH 10/15] Add missing `isNotEqualTo` keyword to validator --- addons/police/functions/fnc_spawnVehicle.sqf | 2 +- tools/sqf_validator.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/police/functions/fnc_spawnVehicle.sqf b/addons/police/functions/fnc_spawnVehicle.sqf index e3c3b3e7..9689337f 100644 --- a/addons/police/functions/fnc_spawnVehicle.sqf +++ b/addons/police/functions/fnc_spawnVehicle.sqf @@ -45,7 +45,7 @@ if (_emptySpawnPointIndex isEqualTo -1) exitWith { private _fullSpawnPointsWithoutCrew = _spawnPoints select { private _nearEntities = getPosATL _x nearEntities SPAWNPOINT_SAFEZONE; if (_nearEntities isEqualTo []) exitWith { false }; - _nearEntities findIf {crew _x isEqualTo []} isNotEqualTo -1; + _nearEntities findIf {crew _x isEqualTo []} isNotEqualTo -1 }; if (_fullSpawnPointsWithoutCrew isEqualTo []) exitWith { diff --git a/tools/sqf_validator.py b/tools/sqf_validator.py index a76b9793..6da3364b 100644 --- a/tools/sqf_validator.py +++ b/tools/sqf_validator.py @@ -12,7 +12,7 @@ open = codecs.open def validKeyWordAfterCode(content, index): - keyWords = ["for", "do", "count", "each", "forEach", "else", "and", "not", "isEqualTo", "in", "call", "spawn", "execVM", "catch", "param", "select", "apply"]; + keyWords = ["for", "do", "count", "each", "forEach", "else", "and", "not", "isEqualTo", "isNotEqualTo", "in", "call", "spawn", "execVM", "catch", "param", "select", "apply"]; for word in keyWords: try: subWord = content.index(word, index, index+len(word)) From e24bfa9b498e23161b54ca3e53c15cafd56672cc Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:17:54 +0100 Subject: [PATCH 11/15] Replace multi-line with single-line comment --- addons/civilian/initSettings.inc.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/civilian/initSettings.inc.sqf b/addons/civilian/initSettings.inc.sqf index ab159779..fb741cf7 100644 --- a/addons/civilian/initSettings.inc.sqf +++ b/addons/civilian/initSettings.inc.sqf @@ -1,4 +1,4 @@ -/* Civilians placement */ +// Civilians placement [ QGVAR(initialCiviliansCount), "SLIDER", From e145ada3f72f7d5d9dec5dcedf572dc4dc7bc03e Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:20:43 +0100 Subject: [PATCH 12/15] List files with docblock --- tools/return_checker.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/return_checker.py b/tools/return_checker.py index 0999077e..f7b5453b 100644 --- a/tools/return_checker.py +++ b/tools/return_checker.py @@ -34,6 +34,7 @@ def filter_files(filepaths): # A possible docblock starts if contents.startswith('/*'): + print(f" INFO: Found docblock in file {filepath}") # Find the `* Return Value:` comment lines = list(map( # Remove \n from all the lines From 30e1b5861e4004ea91b2b1b452f57222c29d1a14 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:24:13 +0100 Subject: [PATCH 13/15] Validate only fnc_*.sqf files --- addons/civilian/initSettings.inc.sqf | 2 +- tools/return_checker.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/civilian/initSettings.inc.sqf b/addons/civilian/initSettings.inc.sqf index fb741cf7..ab159779 100644 --- a/addons/civilian/initSettings.inc.sqf +++ b/addons/civilian/initSettings.inc.sqf @@ -1,4 +1,4 @@ -// Civilians placement +/* Civilians placement */ [ QGVAR(initialCiviliansCount), "SLIDER", diff --git a/tools/return_checker.py b/tools/return_checker.py index f7b5453b..54a42cbf 100644 --- a/tools/return_checker.py +++ b/tools/return_checker.py @@ -15,7 +15,7 @@ def get_files(): sqf_files = [] for root, _, files in os.walk(root_dir): - for file in fnmatch.filter(files, "*.sqf"): + for file in fnmatch.filter(files, "fnc_*.sqf"): sqf_files.append(os.path.join(root, file)) sqf_files.sort() From fb3b194a713bf78f5b5acfc5c84e3766e6fe49d0 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:29:33 +0100 Subject: [PATCH 14/15] Fix return types --- addons/civilian/functions/fnc_createCivilian.sqf | 2 +- addons/civilian/functions/fnc_getNearestCity.sqf | 3 ++- addons/civilian/functions/fnc_getNearestVehicle.sqf | 2 +- addons/civilian/functions/fnc_initCivilian.sqf | 2 ++ addons/common/functions/fnc_deleteAtRandom.sqf | 2 +- addons/common/functions/fnc_getNearestLocationName.sqf | 2 +- addons/common/functions/fnc_getRandomPos.sqf | 2 +- addons/common/functions/fnc_getTextFromConfig.sqf | 2 +- addons/common/functions/fnc_showMessage.sqf | 4 +++- addons/jail/functions/fnc_canRelease.sqf | 2 +- addons/jail/functions/fnc_getRandomJailPos.sqf | 2 +- addons/killers/functions/fnc_anyKillerFree.sqf | 2 +- addons/modules/functions/fnc_initKillersStarts.sqf | 2 +- addons/modules/functions/fnc_initKillersStashes.sqf | 2 +- addons/modules/functions/fnc_initPoliceStations.sqf | 2 +- addons/score/functions/fnc_addPoliceScore.sqf | 2 ++ 16 files changed, 21 insertions(+), 14 deletions(-) diff --git a/addons/civilian/functions/fnc_createCivilian.sqf b/addons/civilian/functions/fnc_createCivilian.sqf index 6731df01..a643c7c6 100644 --- a/addons/civilian/functions/fnc_createCivilian.sqf +++ b/addons/civilian/functions/fnc_createCivilian.sqf @@ -25,4 +25,4 @@ if (_civilian isEqualTo objNull) exitWith { WARNING_2("Failed creating civilian %1 at %2",_unit,_position); }; -[_civilian] call FUNC(initCivilian); +[_civilian] call FUNC(initCivilian) diff --git a/addons/civilian/functions/fnc_getNearestCity.sqf b/addons/civilian/functions/fnc_getNearestCity.sqf index 05cc4fa7..26a60cd3 100644 --- a/addons/civilian/functions/fnc_getNearestCity.sqf +++ b/addons/civilian/functions/fnc_getNearestCity.sqf @@ -27,4 +27,5 @@ _nearestTown = [_position, _searchRadius] call EFUNC(common,getNearestCityLocati // Return city namespace or objNull if not found if (_nearestTown isEqualTo locationNull) exitWith {objNull}; -[_nearestTown] call FUNC(getCityByLocation); + +[_nearestTown] call FUNC(getCityByLocation) diff --git a/addons/civilian/functions/fnc_getNearestVehicle.sqf b/addons/civilian/functions/fnc_getNearestVehicle.sqf index 73753e1e..cb40333c 100644 --- a/addons/civilian/functions/fnc_getNearestVehicle.sqf +++ b/addons/civilian/functions/fnc_getNearestVehicle.sqf @@ -9,7 +9,7 @@ * 2: Filter function returning true for valid vehicles (Optional) * * Return Value: - * None + * Nearest vehicle or objNull if not found * * Example: * [player] call afsk_civilian_fnc_getNearestVehicle diff --git a/addons/civilian/functions/fnc_initCivilian.sqf b/addons/civilian/functions/fnc_initCivilian.sqf index 65c16a83..19675ff4 100644 --- a/addons/civilian/functions/fnc_initCivilian.sqf +++ b/addons/civilian/functions/fnc_initCivilian.sqf @@ -35,3 +35,5 @@ _civilian addEventHandler ["Killed", { [_civilian, _cityNamespace] call FUNC(assignCityCivilian); GVAR(civilians) pushBack _civilian; _civilian setVariable [QGVAR(initialized), true]; + +_civilian diff --git a/addons/common/functions/fnc_deleteAtRandom.sqf b/addons/common/functions/fnc_deleteAtRandom.sqf index fac9b37b..eacf4d78 100644 --- a/addons/common/functions/fnc_deleteAtRandom.sqf +++ b/addons/common/functions/fnc_deleteAtRandom.sqf @@ -17,4 +17,4 @@ params ["_array"]; -_array deleteAt (floor (random (count _array))); +_array deleteAt (floor (random (count _array))) diff --git a/addons/common/functions/fnc_getNearestLocationName.sqf b/addons/common/functions/fnc_getNearestLocationName.sqf index d1db4611..b88731a3 100644 --- a/addons/common/functions/fnc_getNearestLocationName.sqf +++ b/addons/common/functions/fnc_getNearestLocationName.sqf @@ -30,4 +30,4 @@ if (_pos isEqualType objNull) then { private _nearestLocation = [_pos, _searchRadius] call FUNC(getNearestLocationWithAvailableName); if (_nearestLocation isEqualTo locationNull) exitWith {""}; -[_nearestLocation] call FUNC(getLocationName); +[_nearestLocation] call FUNC(getLocationName) diff --git a/addons/common/functions/fnc_getRandomPos.sqf b/addons/common/functions/fnc_getRandomPos.sqf index d362ebba..ed67f5fc 100644 --- a/addons/common/functions/fnc_getRandomPos.sqf +++ b/addons/common/functions/fnc_getRandomPos.sqf @@ -63,4 +63,4 @@ while {(_loopLimit >= 0) && {(_randomPos isEqualTo [])}} do { if (_loopLimit isEqualTo 0) exitWith {[]}; -_randomPos; +_randomPos diff --git a/addons/common/functions/fnc_getTextFromConfig.sqf b/addons/common/functions/fnc_getTextFromConfig.sqf index 122a8aec..a7badd74 100644 --- a/addons/common/functions/fnc_getTextFromConfig.sqf +++ b/addons/common/functions/fnc_getTextFromConfig.sqf @@ -7,7 +7,7 @@ * None * * Return Value: - * None + * Text read from config * * Example: * None diff --git a/addons/common/functions/fnc_showMessage.sqf b/addons/common/functions/fnc_showMessage.sqf index 24ee6aa5..8eb2126c 100644 --- a/addons/common/functions/fnc_showMessage.sqf +++ b/addons/common/functions/fnc_showMessage.sqf @@ -23,4 +23,6 @@ if (GVAR(ACE_Loaded)) then { [_msg, _size, _target, _width] call ACE_common_fnc_displayTextStructured; } else { hint _msg; -} +}; + +nil diff --git a/addons/jail/functions/fnc_canRelease.sqf b/addons/jail/functions/fnc_canRelease.sqf index d4a4802f..63949adb 100644 --- a/addons/jail/functions/fnc_canRelease.sqf +++ b/addons/jail/functions/fnc_canRelease.sqf @@ -8,7 +8,7 @@ * 1: Unit to release * * Return Value: - * None + * Whether target unit can be released * * Example: * [bob, ted] call afsk_jail_fnc_canBeReleased diff --git a/addons/jail/functions/fnc_getRandomJailPos.sqf b/addons/jail/functions/fnc_getRandomJailPos.sqf index 62ea2e45..33689ee7 100644 --- a/addons/jail/functions/fnc_getRandomJailPos.sqf +++ b/addons/jail/functions/fnc_getRandomJailPos.sqf @@ -15,4 +15,4 @@ * Public: No */ -[[[getPosATL GVAR(jail), GVAR(jail) getVariable "objectArea"]], ["water"]] call BIS_fnc_randomPos; +[[[getPosATL GVAR(jail), GVAR(jail) getVariable "objectArea"]], ["water"]] call BIS_fnc_randomPos diff --git a/addons/killers/functions/fnc_anyKillerFree.sqf b/addons/killers/functions/fnc_anyKillerFree.sqf index 8b467f5e..d6aac31d 100644 --- a/addons/killers/functions/fnc_anyKillerFree.sqf +++ b/addons/killers/functions/fnc_anyKillerFree.sqf @@ -7,7 +7,7 @@ * None * * Return Value: - * None + * True if any killer is still free * * Example: * call afsk_killers_fnc_anyKillerFree diff --git a/addons/modules/functions/fnc_initKillersStarts.sqf b/addons/modules/functions/fnc_initKillersStarts.sqf index 29990f1d..8a6b3947 100644 --- a/addons/modules/functions/fnc_initKillersStarts.sqf +++ b/addons/modules/functions/fnc_initKillersStarts.sqf @@ -7,7 +7,7 @@ * None * * Return Value: - * None + * List of killers start modules > * * Example: * None diff --git a/addons/modules/functions/fnc_initKillersStashes.sqf b/addons/modules/functions/fnc_initKillersStashes.sqf index 8aec1857..90b9d979 100644 --- a/addons/modules/functions/fnc_initKillersStashes.sqf +++ b/addons/modules/functions/fnc_initKillersStashes.sqf @@ -7,7 +7,7 @@ * None * * Return Value: - * None + * List of killers stash modules > * * Example: * None diff --git a/addons/modules/functions/fnc_initPoliceStations.sqf b/addons/modules/functions/fnc_initPoliceStations.sqf index 3c56e4ea..963040d2 100644 --- a/addons/modules/functions/fnc_initPoliceStations.sqf +++ b/addons/modules/functions/fnc_initPoliceStations.sqf @@ -7,7 +7,7 @@ * None * * Return Value: - * None + * List of police station modules > * * Example: * None diff --git a/addons/score/functions/fnc_addPoliceScore.sqf b/addons/score/functions/fnc_addPoliceScore.sqf index d551778c..8d8151aa 100644 --- a/addons/score/functions/fnc_addPoliceScore.sqf +++ b/addons/score/functions/fnc_addPoliceScore.sqf @@ -39,3 +39,5 @@ GVAR(policeScoreLastChangeTime) = CBA_missionTime; publicVariable QGVAR(policeScoreChange); }; }, [GVAR(policeScoreChange)], 5] call CBA_fnc_waitAndExecute; + +GVAR(policeScore) From 245845f3064772233759e80be6f72bfeb0bfe392 Mon Sep 17 00:00:00 2001 From: 3Mydlo3 Date: Fri, 27 Dec 2024 17:30:31 +0100 Subject: [PATCH 15/15] Fix stringtable validator prefix --- tools/stringtable_validator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/stringtable_validator.py b/tools/stringtable_validator.py index 207f09d0..01e79971 100644 --- a/tools/stringtable_validator.py +++ b/tools/stringtable_validator.py @@ -16,7 +16,7 @@ ######## GLOBALS ######### -PROJECT_NAME = "AFWG" +PROJECT_NAME = "AFSK" ##########################