From d34c6cd36d687876cd35c3dc5c39e15d259280f3 Mon Sep 17 00:00:00 2001 From: Bastian de Byl Date: Tue, 25 Aug 2026 23:41:00 -0400 Subject: [PATCH] rebuild the Zomboid server on the Sophie 42 preset as "debbzoid" The deployment had drifted badly. It was pinned to the Steam `-beta unstable` branch, which stopped being right the moment B42 became the default at 42.20, and it wrote every mod ID with the `\` prefix that B42 required only during that unstable period and now rejects. Three server profiles were carried around (vanilla, modded, b42revamp) whose mod lists were hand-curated blobs from a Steam collection that has since moved on. Moves to the Sophie 42 community preset, vendored from GerDeathstar/sophie-pz ("Sophie 42 Files.zip", 2026-07-31 == the b42 release tag): 283 mod IDs, 256 workshop items, map_distanciado over Muldraugh, plus its SandboxVars, spawnregions and spawnpoints. Sophie's gameplay settings are kept exactly as shipped -- PVP with its damage modifiers, the safety system, MaxPlayers=32, PauseEmpty, no sleep, safehouses off. Only the keys this deployment actually owns are templated over the top. The modlist is stored as YAML lists rather than the INI's semicolon blobs, so the next Sophie update produces a diff you can read. Exclusions live in zomboid_mods_excluded with a reason each, seeded with IconsInventory -- already absent upstream, listed so a re-vendor cannot quietly bring it back. Config is now seeded before first boot instead of patched after it. The old approach could not write the INI until the server had generated one, so every setting went through lineinfile guarded on a stat; seeding the whole file from the preset removes the chicken-and-egg and puts the config in git. force is off by design: these files are a starting point, not managed state, so the server can be stopped, hand-edited and regenerated without Ansible clobbering the edits. Push them again deliberately with -e zomboid_config_force=true. The B41 Discord keys were dead. B42 replaced DiscordChannel/DiscordChannelID with DiscordChatChannel, which takes a channel name rather than a snowflake, so the DiscordChannelID=... this role had been appending was a key the server ignores and the chat bridge has not been working. Renaming the server to debbzoid is what starts the new world: PZ derives the INI, save directory and player DB from the name, so gregboid stays on disk untouched as a rollback. Re-enabled, because the reason it was off is now fixed. It was disabled for saturating the SSD -- ~10 MB/s of log writes into the shared journal, which starved Gitea CI badly enough to stretch a firmware build to 17 minutes. The container now logs to its own rotating k8s-file instead of the journal every other service shares, and logrotate caps the server's own server-console.txt and Logs/ at 100M keeping 3. copytruncate is mandatory there: PZ holds those fds for its whole life, so a rename would leave it writing into an unlinked inode. Memory is unchanged; idle draw is nowhere near MAX_RAM. Also stops the entrypoint recursively chowning the install tree on every boot. With 256 workshop mods that is a large inode walk and pure churn once the first run has set ownership. Co-Authored-By: Claude Opus 5 (1M context) --- .../common/templates/journald-size.conf.j2 | 5 +- ansible/roles/podman/defaults/main.yml | 83 +- .../files/zomboid/sophie/SandboxVars.lua | 2225 +++++++++++++++++ .../files/zomboid/sophie/spawnpoints.lua | 7 + .../files/zomboid/sophie/spawnregions.lua | 15 + .../podman/tasks/containers/home/zomboid.yml | 170 +- ansible/roles/podman/tasks/main.yml | 3 +- .../podman/templates/zomboid/entrypoint.sh.j2 | 20 +- .../podman/templates/zomboid/install.scmd.j2 | 5 +- .../podman/templates/zomboid/logrotate.j2 | 23 + .../podman/templates/zomboid/server.ini.j2 | 439 ++++ .../templates/zomboid/world-reset.sh.j2 | 2 +- .../roles/podman/vars/zomboid_sophie_mods.yml | 562 +++++ ansible/vars/vault.yml | Bin 34461 -> 34461 bytes scripts/steam-workshop-query.py | 27 +- 15 files changed, 3427 insertions(+), 159 deletions(-) create mode 100644 ansible/roles/podman/files/zomboid/sophie/SandboxVars.lua create mode 100644 ansible/roles/podman/files/zomboid/sophie/spawnpoints.lua create mode 100644 ansible/roles/podman/files/zomboid/sophie/spawnregions.lua create mode 100644 ansible/roles/podman/templates/zomboid/logrotate.j2 create mode 100644 ansible/roles/podman/templates/zomboid/server.ini.j2 create mode 100644 ansible/roles/podman/vars/zomboid_sophie_mods.yml diff --git a/ansible/roles/common/templates/journald-size.conf.j2 b/ansible/roles/common/templates/journald-size.conf.j2 index 160e77a..4ee4abb 100644 --- a/ansible/roles/common/templates/journald-size.conf.j2 +++ b/ansible/roles/common/templates/journald-size.conf.j2 @@ -3,8 +3,9 @@ # 1.9 TB root means it will happily grow into the tens of gigabytes; it had # reached 4 GB before this was set. # -# Every container runs with log_driver=journald, so this is where container -# stdout lands. +# Container stdout lands here: every container runs with log_driver=journald +# except zomboid, which is chatty enough to evict everything else and so gets +# its own rotating k8s-file log instead. {% if graylog_enabled | bool %} # fluent-bit drains the journal into Graylog continuously (systemd input, # _COMM=conmon -- see templates/fluent-bit/fluent-bit.conf.j2), so Graylog is diff --git a/ansible/roles/podman/defaults/main.yml b/ansible/roles/podman/defaults/main.yml index c232b88..d8bb661 100644 --- a/ansible/roles/podman/defaults/main.yml +++ b/ansible/roles/podman/defaults/main.yml @@ -31,48 +31,61 @@ uptime_kuma_path: "{{ podman_volumes }}/uptime-kuma" uptime_kuma_personal_path: "{{ podman_volumes }}/uptime-kuma-personal" zomboid_path: "{{ podman_volumes }}/zomboid" -# Zomboid server mode: 'vanilla', 'modded', or 'b42revamp' -zomboid_server_mode: b42revamp +# Whether to deploy and run the Zomboid server at all. +# +# Was off for months because it was the heaviest tenant on this host: ~9 GB +# resident and ~10 MB/s of continuous log writes, which on a 4-core box also +# running Gitea, Immich, Graylog and two Nextclouds saturated the QLC SSD and +# starved CI -- a firmware build stretched to 17 minutes and one release job +# was killed outright by Gitea's zombie-task timeout. +# +# Back on now that log growth is bounded: the container logs to a rotating +# k8s-file instead of the shared journal, and logrotate caps the server's own +# server-console.txt and Logs/ (see containers/home/zomboid.yml). Memory is +# unchanged -- idle draw is nowhere near MAX_RAM. +# +# Pass -e zomboid_enabled=false to keep it down through a CI-heavy stretch. +# World data under {{ zomboid_path }} is left in place either way. +zomboid_enabled: true + +# Server name, and also the on-disk identity: PZ derives Server/.ini, +# Saves/Multiplayer// and db/.db from it. Renaming it therefore +# starts a brand-new world and leaves the previous one intact for rollback. +zomboid_server_name: debbzoid +zomboid_public_name: Debbzoid + +# Sophie 42 ships map_distanciado as its map mod. Muldraugh must stay last -- +# the base map is the fallback layer. +zomboid_map: "map_distanciado;Muldraugh, KY" # Zomboid RCON port for remote administration zomboid_rcon_port: "27015" -# Server names for each mode -zomboid_server_names: - vanilla: zomboid - modded: moddedjoboid - b42revamp: gregboid +# Discord channel the server's own chat bridge posts into. Build 42 replaced +# B41's DiscordChannel/DiscordChannelID pair with DiscordChatChannel, which +# takes a channel *name*, not a snowflake ID. +zomboid_discord_chat_channel: zomboidbot -# Mod configuration for modded server -# Generated by scripts/steam-workshop-query.py -# Removed: 3403870858 (LifestyleHobbies), 2937786633 (69mini), 3616176188 (GaelGunStore - buggy) -# Removed: 3422418897, 2544353492 (Ahu ToolWeapon - Lua crashes), 2940354599 (FWO Fitness - anim errors) -# Removed: 3390411200 (SLDarkerSnowB42), 3618557184 (HereGoesTheSun) -# Removed: 3480990544 (Constown42), 3602388131 (Greenleaf), 2463499011 (Grapeseed) -# Load order: Libraries first (damnlib, tsarslib), then dependent mods, then others -zomboid_mods: - workshop_items: >- - 3171167894;3402491515;3330403100;2409333430;3073430075;3379334330;3110913021;3366300557;3034636011;3409287192;3005903549;3161951724;3413704851;3413706334;3287727378;3226885926;2625625421;3418252689;3418253716;3152529790;2478247379;2942793445;2991201484;2913633066;2873290424;3428008364;3253385114;2846036306;2642541073;3435796523;3008795514;3447272250;3026723485;2900580391;2870394916;3292659291;2969343830;2566953935;2962175696;3196180339;3258343790;3346905070;3320947974;3478633453;2952802178;3001592312;3052360250;3490370700;2932547723;2805630347;3504401781;2772575623;3110911330;3088951320;3213391371;2932549988;3041122351;2971246021;3539691958;3315443103;2886832257;2886832936;2886833398;2811383142;2799152995;3248388837;3566868353;3570973322;2897390033;3592777775;3596903773;3601417745;3614034284;3577903007;3407042038;3405178154;3402493701;3402812859;3616536783;3431734923;3429790870;2850935956;3307376332;3397182976;3432928943;3610005735;3540297822;3426448380;3579640010;3389448389;3393821407;3044705007;2866258937;3490188370;3508537032;3451167732;3461263912;2903771337;3629835761;3000725405 - # Build 42 requires backslash prefix for each mod ID - # Load order: 1) damnlib 2) tsarslib 3) KI5 vehicles 4) Autotsar vehicles 5) Everything else - mod_ids: >- - \damnlib;\tsarslib;\KI5trailers;\91range;\93fordF350;\82porsche911;\90bmwE30;\91fordLTD;\89dodgeCaravan;\84jeepXJ;\63beetle;\76chevyKseries;\85chevyCaprice;\85pontiacParisienne;\92jeepYJ;\92jeepYJJP18;\87buickRegal;\isoContainers;\85buickLeSabre;\85oldsmobileDelta88;\93chevySuburban;\93chevySuburbanExpanded;\67commando;\90pierceArrow;\69camaro;\70barracuda;\70dodge;\86chevyCUCV;\81deloreanDMC12;\81deloreanDMC12BTTF;\92nissanGTR;\92amgeneralM998;\88toyotaHilux;\91geoMetro;\66pontiacLeMans;\67gt500;\49powerWagon;\86fordE150;\86fordE150dnd;\86fordE150mm;\86fordE150pd;\86fordE150expanded;\89volvo200;\93fordElgin;\86oshkoshP19A;\92fordCVPI;\87chevySuburban;\68firebird;\77firebird;\82firebird;\82firebirdKITT;\04vwTouran;\90fordF350ambulance;\93mustangSSP;\87toyotaMR2;\73fordFalcon;\73fordFalconPS;\93townCar;\84merc;\91nissan240sx;\59meteor;\ECTO1;\87fordB700;\93fordTaurus;\75grandPrix;\89trooper;\63Type2Van;\99fordCVPI;\91fordRanger;\98stagea;\82jeepJ10;\82jeepJ10t;\88chevyS10;\89fordBronco;\83amgeneralM923;\78amgeneralM35A2;\78amgeneralM35A2extra;\78amgeneralM49A2C;\78amgeneralM50A3;\78amgeneralM62;\80manKat1;\65banshee;\89defender;\97bushmaster;\84cadillacDeVille;\84buickElectra;\84oldsmobile98;\85chevyStepVan;\85chevyStepVanexpanded;\autotsartrailers;\ATA_Jeep;\ATA_Jeep_x10;\ATA_Jeep_x2;\ATA_Jeep_x4;\ATA_Mustang;\ATA_Mustang_x2;\ATA_Mustang_x4;\ATA_Bus;\VanillaFoodsExpanded;\TombWardrobeALT;\TombWardrobeALTVanilla;\TombBodyCompat;\TombBodyCompatBootsExp;\TombBody;\TombBodyCustom;\TombBodyTex;\TombBodyTexDOLL;\TombBodyTexNUDE;\SM4BootsExpandedB42;\SM4BootsExpandedFlatshoes;\GanydeBielovzki's Frockin Splendor!;\RandomClothing;\EFTBP;\AliceGear;\TableSaw;\stanks_suicide;\STA_PryOpen;\AutoReload;\DBFaster50;\DBFaster60;\DBFaster70;\DBFaster80;\FixBlowTorchPropaneTank;\MiniHealthPanel;\P4HasBeenRead;\Project_Cook;\NeatUI_Framework;\ModernStatus;\CleanHotBar;\REORDER_THE_HOTBAR;\Ladders42131;\ClimbDownRope +# JVM heap, written into ProjectZomboid64.json by the container entrypoint. +zomboid_min_ram: 8g +zomboid_max_ram: 24g -# B42 Revamp mod configuration (385 mods from Steam Workshop collection) -# Source: https://steamcommunity.com/sharedfiles/filedetails/?id=3672556207 -# Added: LogCabin (3653045510) - player connect/disconnect logging -zomboid_mods_b42revamp: - workshop_items: >- - 3676068610;3673625916;3678008607;2835852387;3597954004;3675740871;2930348946;2392676812;2986578314;3491939136;3044422476;3661387277;3635550823;3438126404;2791949767;3042138819;3464551542;3402491515;3646655397;3389781770;3599368309;3617732907;3608589196;3238830225;3676995511;3502080466;3636185686;3540503606;3497172953;3677217949;3677017550;3428650803;3672451284;3672792485;3651483178;3675741487;3672913009;2925034918;3460812542;3495594275;3668252179;2999595757;3671176591;3576056135;3362348033;3578735933;3594285774;3673222028;2920899878;3622163276;3618427553;3515752079;3478788261;3622328997;3543229299;3402516345;2852704777;3670395687;3671351750;3669550831;3171184800;3171176891;2785549133;2618213077;3639628777;3658421432;3474469914;3669589584;3394378143;3664955167;3651208014;3580557206;3634727573;3652008781;3488113291;3649092715;3651242585;3470485566;3487450124;3153010942;3390487814;3641697417;3421271152;2366717227;3439247001;3322066592;3270190005;3390760692;3470478700;3626008449;3607686447;3637364024;3662731107;3658338529;3655738523;3662733002;3662973331;3669451917;3432928943;3610677934;3538353228;3552050880;3558839307;3560352772;3580577925;3670063857;3670064951;3667630656;3666566299;3668370011;3645687954;3661336777;3528889511;3561017137;3390753141;3482962418;3576150391;3545473388;2879745353;2837923608;3555893112;3496507146;3626823538;3667609521;3342191739;2804531012;3426448380;3360392628;3396446795;3386906181;3573672999;3478633453;2900580391;2772575623;3005903549;3041122351;3566868353;3447272250;2478247379;3026723485;3258343790;2991201484;3631989559;2937786633;2873290424;2913633066;3642935062;3490370700;3213391371;3161951724;3346905070;2799152995;3248388837;3253385114;2886832257;3320947974;3379334330;2811383142;3596903773;3592777775;3409287192;2805630347;3601417745;3418252689;3413704851;3614034284;3330401526;3406622334;3418253716;3413706334;3428008364;2870394916;2566953935;3226885926;3196180339;3110911330;3052360250;2886832936;3658499522;3435796523;3034636011;2886833398;2932549988;3570973322;3292659291;3110913021;2952802178;2942793445;3366300557;3539691958;3008795514;3504401781;2409333430;2642541073;2962175696;3287727378;2846036306;3152529790;2969343830;3073430075;3001592312;3088951320;2932547723;3647735736;3647736504;2897390033;3315443103;2971246021;3630525533;3641027178;3642084851;2584112711;2840805724;3648051123;3646787580;3666180085;3403180543;3268487204;3647039527;3631385356;3632444452;3656054533;3635189378;3469292499;3393821407;3119788162;3387462212;3650168851;3454414190;3567084868;3625933422;3461263912;3437629766;3451167732;3508537032;3490188370;3499049046;3470659758;3044705007;2841969842;2791656602;3453676250;3307376332;3411888105;3431256608;3475347500;3635394848;3538760023;3389115640;3640602763;3640592525;3536052310;3303746488;3315302991;3654107996;3369825662;3299457564;3521263771;3206579556;3309971624;3616192072;3457969588;3443982326;3276134387;3615832618;3610005735;3659676359;1962761540;2335368829;3654929003;3604080281;3609351095;3420478458;2756434288;3616381828;3660382016;3322631319;3628736763;2625625421;3646815505;3629464135;3656507478;3452711271;3428369137;3046728955;3635333613;3651223969;3363546437;3346506593;2896041179;3606927986;3658100636;2447729538;3588624649;3486814612;3602388131;3618557184;3662387304;3653913180;3470422050;3470426196;3403870858;3655692755;3652371248;2934132344;2963467990;2963883586;3248403661;3644794945;2705406713;3423660713;3077900375;3413150945;3623919908;3630693325;3585472912;3627047348;2732294885;3657694399;2535461640;3465040406;3660401764;3645980077;3564950449;3618491765;3388468313;3659543622;3484263516;3656190498;3635591071;3666137359;3290232938;3589560764;3371613588;3414634809;3340255334;2684285534;2463184726;3041733782;2812326159;3628795983;3620003640;3378285185;3650112103;3657325209;3171167894;3037854728;3531765630;3429790870;3431734923;3616536783;3389128453;3330403100;3650071729;3632610172;3640806810;3658745907;3658443845;3658781942;3633882960;3641584634;3631572046;3068955583;3664310933;3554424111;3632872325;3636964628;3582891045;3615422211;3557515648;3577903007;3401134276;3436499337;2757712197;2831786301;2949768076;3418352842;2954956107;3413237147;3423725989;3408186716;3628835042;3624971238;3655089193;3471936625;3653045510 - # Build 42 requires backslash prefix for each mod ID - mod_ids: >- - \VexTVRadio1x;\VexTVRadio1.5x;\VexTVRadio2x;\HB_BLADESMIK05PS;\Disassemble Container With Items;\Disassemble Container With Items 42 Fix;\DeadMansDossier;\GarageDoors;\2392676812/lgd_antibodies;\TchernoLib;\Bandit_Zombies_Expanded;\ScottsJumperCables;\R.U. BTR-80 by Papa_Chad;\R.U. BMP-2 by Papa_Chad;\NepHighBeams;\GWagen;\TrueMusicJukebox;\FunctionalAppliances2;\FunctionalCarLift;\tsarslib;\B421977VAZ2121;\enhanced_flashlight_glow;\PainSense;\ItemInspectionUI;\SprintersOverTime;\Real Firearms;\PZShareMapNotes;\Neat_Crafting;\CamisetasSeleccion;\Neat_Building_AddonXP;\Neat_Crafting_AddonXP;\[J&G] Neon Vandals Uniform;\1967ChevyImpala;\TacHold;\TacHold AR;\MoneyFromCreditCards;\JeevesDrops;\HelicopterEventExpansionFramework;\PLAYDOOM;\[J&G] Umbrella Corp Uniform;\OcciferCodys_RainWashesVehicles;\2925034918/EasyLaundry;\WashFix;\LanternFix;\DentalFlossIcon;\Wallpapers;\WallpapersBM;\WallpapersOLD;\dustinguished_bolt_cutters;\BetterGeneratorInfo;\[J&G] Jordan's Tailoring Buff;\GenStreetlightRestore;\hydecoautomaticgaragedoors;\WMTBoat;\ReloadAllMagazines;\RVInteriorExpansionPart2;\RVInteriorExpansion;\My90s;\Meiya'sTown;\AdaptiveTraits;\PROJECTRVInterior42;\B42Survival;\simonMDsTiles;\serenitybunker;\HardwoodsTurnoutGear;\ProximityInventory;\84gageV300;\49ford8N;\74amgeneralM151A2;\82oshkoshM911;\BurdSurvivalJournals;\BanditsFix;\BanditsFirearms;\BanditsFrockin;\[B42]PumpsHavePropane-transplant;\ForceSprinters;\ForceSprinters100;\ForceSprintersLocations;\PTBR_KI5damnlib;\dailystatisticsandgains;\RAF;\ExtraBombs2;\DarkWpnSlings;\InvisibleWpnSlings;\zReArmorPackBYKB42;\NWMF1;\LynxPack;\FeedThatAnimal;\FirstAidVHSTapes;\DEON_CVG;\Reading+;\1VCESTANDARD;\1VCESTANDARDNOMP;\1VCESTANDARDPre42;\SwapIt;\MilitaryPonchosRELOADED;\AatheomEMVFSM;\DetailedFootwear;\CerberusPack;\PlumbingFixed;\ImmersiveBlackouts;\ImmersiveBlackoutsRandomSupply;\HBAC;\HBACVFE;\HBACVFE93;\HBACVFES;\70barracudaRusty;\85chevyStepVanexpandedRusty;\85chevyStepVanRusty;\91fordLTDRusty;\KI5trailersRusty;\TM_PopCulture;\Snowman;\EFTBP;\HBVCEFb42;\LBB42;\LFB42;\LDB42;\LSB42;\LNB42;\70fordEscort;\KI5campers;\HellDrinxEssentials;\BlackstoneMapMod;\LKB42;\MoodleFramework_SafetyPatch;\Horse;\BananaBeachHouse;\PeaceTown;\Daisy County B42 version;\Daisy County B42 version(items part);\Asakusa lake town;\Cathaya Valley 2.0 B42 version;\Cathaya Valley 2.0 B42 version highway;\IrisEyot;\melos_tiles_for_miles_pack;\PertsPartyTiles;\GreenRiver;\muldraughmilitarybaseas24;\OCsPacking;\FasterSeatedReading;\GydeTraitMags;\DRAW_ON_MAP;\stanks_suicide;\mapmodmanager;\MoodleFramework;\SandboxSettings;\sandboxpresetsaver;\04vwTouran;\49powerWagon;\59meteor;\ECTO1;\63beetle;\63Type2Van;\65banshee;\66pontiacLeMans;\67commando;\67gt500;\68firebird;\69camaro;\69charger;\69mini;\69mini_ItalianJob;\69mini_MrBean;\69mini_PitbullSpecial;\70dodge;\70barracuda;\70roadRunner;\73fordFalcon;\73fordFalconPS;\75grandPrix;\76chevyKseries;\77firebird;\78amgeneralM35A2;\78amgeneralM35A2extra;\78amgeneralM49A2C;\78amgeneralM50A3;\78amgeneralM62;\80manKat1;\81deloreanDMC12;\81deloreanDMC12BTTF;\82jeepJ10;\82jeepJ10t;\82firebird;\82firebirdKITT;\82porsche911;\83amgeneralM923;\84buickElectra;\84cadillacDeVille;\84jeepXJ;\84merc;\84oldsmobile98;\85buickLeSabre;\85chevyCaprice;\85chevyStepVan;\85chevyStepVanexpanded;\85clubMan;\isg85countach;\85oldsmobileDelta88;\85pontiacParisienne;\86chevyCUCV;\86fordE150;\86fordE150dnd;\86fordE150mm;\86fordE150pd;\86fordE150expanded;\86oshkoshP19A;\87buickRegal;\87chevySuburban;\87fordB700;\87toyotaMR2;\88chevyS10;\88chevyS10Rusty;\88toyotaHilux;\89dodgeCaravan;\89fordBronco;\89trooper;\89defender;\89volvo200;\90bmwE30;\90fordF350ambulance;\90pierceArrow;\91fordLTD;\91fordRanger;\91geoMetro;\91nissan240sx;\91range;\92amgeneralM998;\92fordCVPI;\92jeepYJ;\92jeepYJJP18;\92nissanGTR;\93chevySuburban;\93chevySuburbanExpanded;\93fordElgin;\93fordF350;\93mustangSSP;\93fordTaurus;\93townCar;\95impreza;\96lancerEVO;\97bushmaster;\98stagea;\99fordCVPI;\ZWatchSlots;\UnclearRipAllButton;\MinimalSidebar;\FasterHoodOpening;\SimpleOverhaulTraitsAndOccupations;\InjuredZombiesStumble;\ThumpingAttractsZombies;\dawn_town;\BanditsWeekOne;\Bandits2;\42GunReloadFix;\BanditsWeekOneMultiplayer;\PumpsHavePropaneMP;\MoreMapsB42;\SEG_Animalsdonotthump;\BanditsCreator;\DBFaster50;\DBFaster60;\DBFaster70;\DBFaster80;\Optimal;\Performance;\extendedBatteryLife;\B42Horticulture;\AccCamos;\AccCamosPeriodPack;\ModManager;\FixedLightOnBeltAF;\CleanHotBar;\CleanUI;\ModernStatus;\NeatUI_Framework;\Project_Cook;\[B42]PumpsHavePropane_fix;\TheShortcut;\FixBlowTorchPropaneTank;\fhqHotPursuit;\fhqHotPursuitRealNames;\fhqMotoriousZone;\fhqMotoriousZoneImports;\fhqMotoriousZoneExotics;\fhqMotoriousZoneRealNames;\fhqMotoriousZoneUSDM;\GanydeBielovzki's Frockin Shirts n Ties;\GanydeBielovzki's Frockin Splendor!;\GanydeBielovzki's Frockin Splendor! Vol.2;\GanydeBielovzki's Frockin Splendor! Vol.3;\GanydeBielovzki's Frockin Splendor! Vol.4;\GanydeBielovzki's Frockin Splendor! Vol.5;\GanydeBielovzki's Frockin Wiseguys;\TakeAnyAmount;\Animal_Essentials;\KITTYOWO;\Neat_Building;\[J&G] Alpine Multicam Uniform;\[J&G] Black Multicam Uniform;\[J&G] British DPM Uniform;\[J&G] Caution Pack;\[J&G] Desert Multicam Uniform;\[J&G] Firefighter Uniform;\[J&G] Flecktarn Uniform;\[J&G] Forest Multicam Uniform;\[J&G] MARPAT Camo Uniform;\[J&G] SWAT Uniform;\[J&G] Trauma Responder Uniform;\[J&G] XKU Uniform;\RadioBrasil;\AliceGear;\AnruisiTown;\ArmoredVestsPatch;\ArmoredVests;\AuthenticZBackpacks+;\Authentic Z - Current;\AuthenticZLite;\vac_mod_b42_4;\EURY_CLOTHINGINFO;\EURY_COOKINGUI;\BetterFlashlightsFixed;\ClientModsToServer;\BlueMoonLightingMod;\BCR;\PompCollectibles;\UnofficialMappersCommunityTilePack;\isoContainers;\CustomSync;\CustomizableWeightMultiplierContinued;\CYBERDOGTEMPLATE;\H_E_C_U;\NepWreckWorkingCars;\tikitown_tiles;\DynamicTradingCommon;\DynamicTrading;\DynamicTradingV2;\Energy Drinks ZreApo B42.13+;\Erikas_Furniture_Store;\Erikas_Tiles;\errorMagnifier;\Estate 39;\Fallout Hummer by Papa_Chad;\FH;\FordExcursion2005PapaChad;\Fort Waterfront B42;\Greenleaf B42 version;\HereGoesTheSun;\ItemRarityUI;\Karas Zone Selector API;\KATTAJ1_ClothesCore;\KATTAJ1_Military;\LifestyleHobbies;\LinkinParkGreatestHits2012;\lockMartM577;\Louisville_Quarantine_Zone;\Louisville_River_Marina;\Louisville_Riverboat;\mapcursorcord;\Maplewood;\Military_Tool_Kit;\ModLoadOrderSorter_b42;\ChuckleberryFinnAlertSystem;\MoreDamagedObjects;\MoreDescriptionForTraits4213;\CargoTrailer_BubbysVariants;\beek_muldraugh_firedept;\EURY_BUGS;\NamedSkillVHSTapes;\newclothesmodels;\NoVanillaDuplicates;\NoVanillaProf;\NoVanillaVehicles;\NoVanillaStoriesKI5+Filibuster;\NoVanillaStoriesKI5;\OpenAllContainers;\vac_mod_b42_22;\ProjectArcade;\ProjectSummerCar;\ItemretexturePSC;\RaccoonCityB42;\Kaldo_RadioFrequencyManagerB42;\RavenCreekB42;\ReactiveSE;\RealisticDash;\Roccos_Tiles;\SmarterStorage;\SnackTime89;\SLDarkerSnow;\SpnCharCustom;\SPNCC;\SpnCharCustomDetails;\SPNCCDetails;\SpnCharCustomDetailsHD;\SPNCCDetailsHD;\SpnCharCustomFaces;\SPNCCFaces;\SPNRetexture;\SPNRetextureCustom;\SPNRetextureUnderwear;\SPNRetextureZombie;\SPNRetextureZombieUnderwear;\SpnCloth;\SpnHair;\SpnHairAPI;\SpnOpenCloth;\StarWarsEntireOriginalTrilogyonvhs;\StarWarsEntirePrequelTrilogyonvhs;\StarlitLibrary;\StopJumpingOffStairs;\StorageWorks;\damnlib;\tikitown;\TikitownPower;\TombGothHair;\TombGothMakeup;\TombGothTex;\TombGothTexDOLL;\TombGothTexNUDE;\TombBody;\TombBodyCustom;\TombBodyTex;\TombBodyTexDOLL;\TombBodyTexNUDE;\TombBodyCompat;\TombBodyCompatBootsExp;\TombWardrobeALT;\TombWardrobeALTVanilla;\PTBRB42;\KI5trailers;\TrueActionsDancing;\TrueMusicRadio42;\TMMumble;\TrueMoozic;\TM_Metallica;\TM_TrueMooZicGunsNRosesUseYourIllus;\TM_TrueMooZicMichaelJacksonOfftheWa;\TM_TrueMooZicMichaelJacksonThriller;\TMMMB42.13+;\TMItemMPSyncFix;\TMRRemoveMumble42;\truemusic_mixtape_megapack;\TwoWeaponsB;\U.S. M998 Humvee by Papa_Chad;\ukr_melee_42;\Uncleredsbunkerb42;\UncleRedsBunkerRedux;\UnseasonalWeather;\UseItemsWhileWalkingB42;\vac_mod_b42_utils;\vac_playing_utils;\VanillaFoodsExpanded;\VanillaGearExpanded;\VMZNEW;\VMZ;\VehicleRepairOverhaul;\VehicleSalvageOverhaulB42;\Video_Game_Consoles;\VGC_Addon_GameBoyGames;\VGC_Addon_NESGames;\VGC_Addon_SEGAGames;\VGC_Addon_SNESGames;\VGC_Addon_SNESGames2;\WorkshopUpdateCheck;\YAPZLib;\TM_ZAMN;\zReApoPonchosB42;\LogCabin +# The modlist itself lives in vars/zomboid_sophie_mods.yml -- 283 mod IDs and +# 256 workshop items vendored from the upstream Sophie 42 preset. +zomboid_preset_version: "sophie-42 @ 2026-07-31" -# Map configuration per server mode -zomboid_maps: - vanilla: "Muldraugh, KY" - modded: "Muldraugh, KY" - b42revamp: "AnruisiTown;Asakusa lake town;BananaBeachHouse;Blackstone;Cathaya Valley2.0;Cathaya Valley2.0 highway;Daisy County;DawnTown;Estate 39;Fort Waterfront B42;Greenleaf;GreenRiver;IrisEyot;Louisville_Quarantine_Zone;Louisville_River_Marina;Louisville_Riverboat;Maplewood;Meiya'sTown;Muldraugh_FireDept;muldraughmilitarybaseas24;PeaceTown;RaccoonCity;Raven Creek B42;map_distanciado;rvupdate;rv2;serenitybunker;Tikitown;Uncle Red's Bunker B42;Uncle Red's Bunker Redux B42;WestPoint-MilitaryTugBoat;Muldraugh, KY" +# Mods subtracted from the vendored Sophie lists before they reach the INI. +# Explicit and reasoned so that re-vendoring a newer preset cannot silently +# reintroduce something we deliberately dropped. +zomboid_mods_excluded: + # Already absent from the 2026-07-31 preset; listed so it stays that way. + - workshop_id: "3718412967" + mod_id: IconsInventory + reason: Sophie recommends removing Icon Inventory + +# Server config is seeded once and then left alone, so it can be hand-edited +# between world regenerations. Set true to overwrite it from the templates. +zomboid_config_force: false sshpass_cron_path: "{{ podman_volumes }}/sshpass_cron" caddy_path: "{{ podman_volumes }}/caddy" diff --git a/ansible/roles/podman/files/zomboid/sophie/SandboxVars.lua b/ansible/roles/podman/files/zomboid/sophie/SandboxVars.lua new file mode 100644 index 0000000..cb5c9d2 --- /dev/null +++ b/ansible/roles/podman/files/zomboid/sophie/SandboxVars.lua @@ -0,0 +1,2225 @@ +SandboxVars = { + VERSION = 6, + -- Changing this also sets the "Population Multiplier" in Advanced Zombie Options. Default = Normal + -- 1 = Insane + -- 2 = Very High + -- 3 = High + -- 4 = Normal + -- 5 = Low + -- 6 = None + Zombies = 4, + -- How zombies are distributed across the map. Default = Urban Focused + -- 1 = Urban Focused + -- 2 = Uniform + Distribution = 1, + -- Controls whether some randomization is applied to zombie distribution. + ZombieVoronoiNoise = true, + -- How frequently new zombies are added to the world. Default = None + -- 1 = High + -- 2 = Normal + -- 3 = Low + -- 4 = None + ZombieRespawn = 4, + -- Zombie allowed to migrate to empty cells. + ZombieMigrate = true, + -- Default = 1 Hour, 30 Minutes + -- 1 = 15 Minutes + -- 2 = 30 Minutes + -- 3 = 1 Hour + -- 4 = 1 Hour, 30 Minutes + -- 5 = 2 Hours + -- 6 = 3 Hours + -- 7 = 4 Hours + -- 8 = 5 Hours + -- 9 = 6 Hours + -- 10 = 7 Hours + -- 11 = 8 Hours + -- 12 = 9 Hours + -- 13 = 10 Hours + -- 14 = 11 Hours + -- 15 = 12 Hours + -- 16 = 13 Hours + -- 17 = 14 Hours + -- 18 = 15 Hours + -- 19 = 16 Hours + -- 20 = 17 Hours + -- 21 = 18 Hours + -- 22 = 19 Hours + -- 23 = 20 Hours + -- 24 = 21 Hours + -- 25 = 22 Hours + -- 26 = 23 Hours + -- 27 = Real-time + DayLength = 4, + StartYear = 1, + -- Month in which the game starts. Default = July + -- 1 = January + -- 2 = February + -- 3 = March + -- 4 = April + -- 5 = May + -- 6 = June + -- 7 = July + -- 8 = August + -- 9 = September + -- 10 = October + -- 11 = November + -- 12 = December + StartMonth = 7, + -- Day of the month in which the games starts. + StartDay = 9, + -- Hour of the day in which the game starts. Default = 9 AM + -- 1 = 7 AM + -- 2 = 9 AM + -- 3 = 12 PM + -- 4 = 2 PM + -- 5 = 5 PM + -- 6 = 9 PM + -- 7 = 12 AM + -- 8 = 2 AM + -- 9 = 5 AM + StartTime = 2, + -- Whether the time of day changes naturally, or it's always day/night. Default = Normal + -- 1 = Normal + -- 2 = Endless Day + -- 3 = Endless Night + DayNightCycle = 1, + -- Whether weather changes or remains at a single state. Default = Normal + -- 1 = Normal + -- 2 = No Weather + -- 3 = Endless Rain + -- 4 = Endless Storm + -- 5 = Endless Snow + -- 6 = Endless Blizzard + ClimateCycle = 1, + -- Whether fog occurs naturally, never occurs, or is always present. Default = Normal + -- 1 = Normal + -- 2 = No Fog + -- 3 = Endless Fog + FogCycle = 1, + -- How long after the default start date (July 9, 1993) that plumbing fixtures (eg. sinks) stop being infinite sources of water. Default = 0 - 30 Days + -- 1 = Instant + -- 2 = 0 - 30 Days + -- 3 = 0 - 2 Months + -- 4 = 0 - 6 Months + -- 5 = 0 - 1 Year + -- 6 = 0 - 5 Years + -- 7 = 2 - 6 Months + -- 8 = 6 - 12 Months + -- 9 = Disabled + WaterShut = 2, + -- How long after the default start date (July 9, 1993) that the world's electricity turns off for good. Default = 14 - 30 Days + -- 1 = Instant + -- 2 = 14 - 30 Days + -- 3 = 14 Days - 2 Months + -- 4 = 14 Days - 6 Months + -- 5 = 14 Days - 1 Year + -- 6 = 14 Days - 5 Years + -- 7 = 2 - 6 Months + -- 8 = 6 - 12 Months + -- 9 = Disabled + ElecShut = 2, + -- How long alarm batteries can last for after the power shuts off. Default = 0 - 30 Days + -- 1 = Instant + -- 2 = 0 - 30 Days + -- 3 = 0 - 2 Months + -- 4 = 0 - 6 Months + -- 5 = 0 - 1 Year + -- 6 = 0 - 5 Years + AlarmDecay = 2, + -- How long after the default start date (July 9, 1993) that plumbing fixtures (eg. sinks) stop being infinite sources of water. Min: -1 Max: 2147483647 Default: 14 + WaterShutModifier = 14, + -- How long after the default start date (July 9, 1993) that the world's electricity turns off for good. Min: -1 Max: 2147483647 Default: 14 + ElecShutModifier = 14, + -- How long alarm batteries can last for after the power shuts off. Min: -1 Max: 2147483647 Default: 14 + AlarmDecayModifier = 14, + -- Any food that can rot or spoil. Min: 0.00 Max: 4.00 Default: 0.80 + FoodLootNew = 0.5, + -- All other items that can be read, including books, fliers, and newspapers. Min: 0.00 Max: 4.00 Default: 0.60 + LiteratureLootNew = 0.4, + -- Books that provide skill XP multipliers. Min: 0.00 Max: 4.00 Default: 0.60 + SkillBookLoot = 0.3, + -- Items that teach recipes. Min: 0.00 Max: 4.00 Default: 0.60 + RecipeResourceLoot = 0.35, + -- Medicine, bandages and first aid tools. Min: 0.00 Max: 4.00 Default: 0.60 + MedicalLootNew = 0.4, + -- Fishing Rods, Tents, camping gear etc. Min: 0.00 Max: 4.00 Default: 0.60 + SurvivalGearsLootNew = 0.4, + -- Canned and dried food, beverages. Min: 0.00 Max: 4.00 Default: 0.60 + CannedFoodLootNew = 0.3, + -- Weapons that are not tools in other categories. Min: 0.00 Max: 4.00 Default: 0.60 + WeaponLootNew = 0.35, + -- Also includes weapon attachments. Min: 0.00 Max: 4.00 Default: 1.20 + RangedWeaponLootNew = 0.15, + -- Loose ammo, boxes and magazines. Min: 0.00 Max: 4.00 Default: 0.60 + AmmoLootNew = 0.5, + -- Vehicle parts and the tools needed to install them. Min: 0.00 Max: 4.00 Default: 0.60 + MechanicsLootNew = 0.4, + -- Everything else. Also affects foraging for all items in Town/Road zones. Min: 0.00 Max: 4.00 Default: 0.80 + OtherLootNew = 0.7, + -- All wearable items that are not containers. Min: 0.00 Max: 4.00 Default: 0.60 + ClothingLootNew = 0.3, + -- Backpacks and other wearable/equippable containers, eg. cases. Min: 0.00 Max: 4.00 Default: 0.60 + ContainerLootNew = 0.2, + -- Keys for buildings/cars, key rings, and locks. Min: 0.00 Max: 4.00 Default: 0.40 + KeyLootNew = 0.35, + -- VHS tapes and CDs. Min: 0.00 Max: 4.00 Default: 0.60 + MediaLootNew = 0.3, + -- Spiffo items, plushies, and other collectible keepsake items eg. Photos. Min: 0.00 Max: 4.00 Default: 0.60 + MementoLootNew = 0.35, + -- Items that are used in cooking, including those (eg. knives) which can be weapons. Does not include food. Includes both usable and unusable items. Min: 0.00 Max: 4.00 Default: 0.60 + CookwareLootNew = 0.35, + -- Items and weapons that are used as ingredients for crafting or building. This is a general category that does not include items belonging to other categories such as Cookware or Medical. Does not include Tools. Min: 0.00 Max: 4.00 Default: 0.60 + MaterialLootNew = 0.4, + -- Items and weapons which are used in both animal and plant agriculture, such as Seeds, Trowels, or Shovels. Min: 0.00 Max: 4.00 Default: 0.60 + FarmingLootNew = 0.3, + -- Items and weapons which are Tools but don't fit in other categories such as Mechanics or Farming. Min: 0.00 Max: 4.00 Default: 0.60 + ToolLootNew = 0.4, + -- [!] It is recommended that you DO NOT change this. [!] Can be used to adjust the number of rolls made on loot tables when spawning loot. Will not reduce the number of rolls below 1. Can negatively affect performance if set to high values. It is highly recommended that this not be changed. Min: 0.10 Max: 100.00 Default: 1.00 + RollsMultiplier = 1.0, + -- A comma-separated list of item types that won't spawn as ordinary loot. + LootItemRemovalList = "", + -- If enabled, items on the Loot Item Removal List, or that have their rarity set to 'None', will not spawn in randomised world stories. + RemoveStoryLoot = false, + -- If enabled, items on the Loot Item Removal List, or that have their rarity set to 'None', will not spawn worn by, or attached to, zombies. + RemoveZombieLoot = false, + -- If greater than 0, the spawn of loot is increased relative to the number of nearby zombies, with the effect multiplied by this number. Min: 0 Max: 20 Default: 0 + ZombiePopLootEffect = 0, + -- Min: 0.00 Max: 0.20 Default: 0.05 + InsaneLootFactor = 0.05, + -- Min: 0.05 Max: 0.60 Default: 0.20 + ExtremeLootFactor = 0.2, + -- Min: 0.20 Max: 1.00 Default: 0.60 + RareLootFactor = 0.6, + -- Min: 0.60 Max: 2.00 Default: 1.00 + NormalLootFactor = 1.0, + -- Min: 1.00 Max: 3.00 Default: 2.00 + CommonLootFactor = 2.0, + -- Min: 2.00 Max: 4.00 Default: 3.00 + AbundantLootFactor = 3.0, + -- The global temperature. Default = Normal + -- 1 = Very Cold + -- 2 = Cold + -- 3 = Normal + -- 4 = Hot + -- 5 = Very Hot + Temperature = 3, + -- How often it rains. Default = Normal + -- 1 = Very Dry + -- 2 = Dry + -- 3 = Normal + -- 4 = Rainy + -- 5 = Very Rainy + Rain = 3, + -- Number of days until the erosion system (which adds vines, long grass, new trees etc. to the world) will reach 100% growth. Default = Slow (200 Days) + -- 1 = Very Fast (20 Days) + -- 2 = Fast (50 Days) + -- 3 = Normal (100 Days) + -- 4 = Slow (200 Days) + -- 5 = Very Slow (500 Days) + ErosionSpeed = 4, + -- For a custom Erosion Speed. Zero means use the Erosion Speed option. Maximum is 36,500 days (approximately 100 years). Min: -1 Max: 36500 Default: 0 + ErosionDays = 0, + -- The speed of plant growth. Default = Normal + -- 1 = Very Fast + -- 2 = Fast + -- 3 = Normal + -- 4 = Slow + -- 5 = Very Slow + Farming = 3, + -- How long it takes for food to break down in a composter. Default = 2 Weeks + -- 1 = 1 Week + -- 2 = 2 Weeks + -- 3 = 3 Weeks + -- 4 = 4 Weeks + -- 5 = 6 Weeks + -- 6 = 8 Weeks + -- 7 = 10 Weeks + -- 8 = 12 Weeks + CompostTime = 2, + -- How fast the player's hunger, thirst, and fatigue will decrease. Default = Normal + -- 1 = Very Fast + -- 2 = Fast + -- 3 = Normal + -- 4 = Slow + -- 5 = Very Slow + StatsDecrease = 3, + -- The abundance of items found in Foraging mode. Default = Normal + -- 1 = Very Poor + -- 2 = Poor + -- 3 = Normal + -- 4 = Abundant + -- 5 = Very Abundant + NatureAbundance = 3, + -- How likely the player is to activate a house alarm when breaking into a new house. Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + Alarm = 4, + -- How frequently the doors of homes and buildings will be locked when discovered. Default = Very Often + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + LockedHouses = 6, + -- Spawn with Chips, a Water Bottle, a Small Backpack, a Baseball Bat, and a Hammer. + StarterKit = false, + -- Nutritional value of food affects the player's condition. Turning this off will stop the player gaining or losing weight. + Nutrition = true, + -- How fast that food will spoil, inside or outside of a fridge. Default = Normal + -- 1 = Very Fast + -- 2 = Fast + -- 3 = Normal + -- 4 = Slow + -- 5 = Very Slow + FoodRotSpeed = 3, + -- How effective a fridge will be at keeping food fresh for longer. Default = Normal + -- 1 = Very Low + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + -- 6 = No decay + FridgeFactor = 3, + -- When greater than 0, loot will not respawn in zones that have been visited within this number of in-game hours. Min: 0 Max: 2147483647 Default: 0 + SeenHoursPreventLootRespawn = 0, + -- When greater than 0, after X hours, all containers in towns and trailer parks in the world will respawn loot. To spawn loot a container must have been looted at least once. Loot respawn is not impacted by visibility or subsequent looting. Min: 0 Max: 2147483647 Default: 0 + HoursForLootRespawn = 0, + -- Containers with a number of items greater, or equal to, this setting will not respawn. Min: 0 Max: 2147483647 Default: 5 + MaxItemsForLootRespawn = 5, + -- Items will not respawn in buildings that players have barricaded or built in. + ConstructionPreventsLootRespawn = true, + -- A comma-separated list of item types that will be removed after HoursForWorldItemRemoval hours. + WorldItemRemovalList = "Base.Hat, Base.Glasses, Base.Maggots, Base.Slug, Base.Slug2, Base.Snail, Base.Worm, Base.Dung_Mouse, Base.Dung_Rat", + -- Number of hours since an item was dropped on the ground before it is removed. Items are removed the next time that part of the map is loaded. Zero means items are not removed. Min: 0.00 Max: 2147483647.00 Default: 24.00 + HoursForWorldItemRemoval = 24.0, + -- If true, any items *not* in WorldItemRemovalList will be removed. + ItemRemovalListBlacklistToggle = false, + -- How long after the end of the world to begin. This will affect starting world erosion and food spoilage. Does not affect the starting date. Default = 0 + -- 1 = 0 + -- 2 = 1 + -- 3 = 2 + -- 4 = 3 + -- 5 = 4 + -- 6 = 5 + -- 7 = 6 + -- 8 = 7 + -- 9 = 8 + -- 10 = 9 + -- 11 = 10 + -- 12 = 11 + -- 13 = 12 + TimeSinceApo = 1, + -- How much water plants will lose per day, and their ability to avoid disease. Default = Normal + -- 1 = Very High + -- 2 = High + -- 3 = Normal + -- 4 = Low + -- 5 = Very Low + PlantResilience = 3, + -- The yield of plants when harvested. Default = Normal + -- 1 = Very Poor + -- 2 = Poor + -- 3 = Normal + -- 4 = Abundant + -- 5 = Very Abundant + PlantAbundance = 3, + -- Recovery from being tired after performing actions. Default = Normal + -- 1 = Very Fast + -- 2 = Fast + -- 3 = Normal + -- 4 = Slow + -- 5 = Very Slow + EndRegen = 3, + -- How regularly a helicopter passes over the Event Zone. Default = Once + -- 1 = Never + -- 2 = Once + -- 3 = Sometimes + -- 4 = Often + Helicopter = 2, + -- How often zombie-attracting metagame events like distant gunshots will occur. Default = Sometimes + -- 1 = Never + -- 2 = Sometimes + -- 3 = Often + MetaEvent = 2, + -- How often events during the player's sleep, like nightmares, occur. Default = Never + -- 1 = Never + -- 2 = Sometimes + -- 3 = Often + SleepingEvent = 1, + -- How much fuel is consumed by generators per in-game hour. Min: 0.00 Max: 100.00 Default: 0.10 + GeneratorFuelConsumption = 0.1, + -- The chance of electrical generators spawning on the map. Default = Rare + -- 1 = None (not recommended) + -- 2 = Insanely Rare + -- 3 = Extremely Rare + -- 4 = Rare + -- 5 = Normal + -- 6 = Common + -- 7 = Abundant + GeneratorSpawning = 3, + -- How often a looted map will have notes on it, written by a deceased survivor. Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + AnnotatedMapChance = 4, + -- Adds free points during character creation. Min: -100 Max: 100 Default: 0 + CharacterFreePoints = 0, + -- Gives player-built constructions extra hit points so they are more resistant to zombie damage. Default = Normal + -- 1 = Very Low + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + ConstructionBonusPoints = 3, + -- The level of ambient lighting at night. Default = Normal + -- 1 = Pitch Black + -- 2 = Dark + -- 3 = Normal + -- 4 = Bright + NightDarkness = 3, + -- The time from dusk to dawn. Default = Normal + -- 1 = Always Night + -- 2 = Long + -- 3 = Normal + -- 4 = Short + -- 5 = Always Day + NightLength = 3, + -- If survivors can get broken limbs from impacts, zombie damage, falls etc. + BoneFracture = true, + -- The impact that injuries have on your body, and their healing time. Default = Normal + -- 1 = Low + -- 2 = Normal + -- 3 = High + InjurySeverity = 2, + -- How long, in hours, before dead zombie bodies disappear from the world. If 0, maggots will not spawn on corpses. Min: -1.00 Max: 2147483647.00 Default: 216.00 + HoursForCorpseRemoval = 160.0, + -- The impact that nearby decaying bodies has on the player's health and emotions. Default = Normal + -- 1 = None + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Insane + DecayingCorpseHealthImpact = 4, + -- Whether nearby "living" zombies have the same impact on the player's health and emotions. + ZombieHealthImpact = false, + -- How much blood is sprayed on floors and walls by injuries. Default = Normal + -- 1 = None + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Ultra Gore + BloodLevel = 3, + -- How quickly clothing degrades, becomes dirty, and bloodied. Default = Normal + -- 1 = Disabled + -- 2 = Slow + -- 3 = Normal + -- 4 = Fast + ClothingDegradation = 3, + -- If fires spread when started. + FireSpread = true, + -- Number of in-game days before rotten food is removed from the map. -1 means rotten food is never removed. Min: -1 Max: 2147483647 Default: -1 + DaysForRottenFoodRemoval = -1, + -- If enabled, generators will work on exterior tiles. This will allow, for example, the powering of gas pumps. + AllowExteriorGenerator = true, + -- Maximum intensity of fog. Default = Normal + -- 1 = Normal + -- 2 = Moderate + -- 3 = Low + -- 4 = None + MaxFogIntensity = 1, + -- Maximum intensity of rain. Default = Normal + -- 1 = Normal + -- 2 = Moderate + -- 3 = Low + MaxRainFxIntensity = 1, + -- If snow will accumulate on the ground. If disabled, snow will still show on vegetation and rooftops. + EnableSnowOnGround = true, + -- If melee attacking slows you down. + AttackBlockMovements = true, + -- The chance of finding randomized buildings on the map (eg. burnt out houses, ones containing loot stashes or dead bodies). Default = Rare + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always Tries + SurvivorHouseChance = 2, + -- The chance of road stories (eg. police roadblocks) spawning. Default = Rare + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always Tries + VehicleStoryChance = 3, + -- The chance of stories specific to map zones (eg. a campsite in a forest) spawning. Default = Rare + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always Tries + ZoneStoryChance = 3, + -- Allows you to select from every piece of clothing in the game when customizing your character + AllClothesUnlocked = false, + -- If tainted water will show a warning marking it as such. + EnableTaintedWaterText = true, + -- If vehicles will spawn. + EnableVehicles = true, + -- How frequently vehicles can be discovered on the map. Default = Low + -- 1 = None + -- 2 = Very Low + -- 3 = Low + -- 4 = Normal + -- 5 = High + CarSpawnRate = 3, + -- General engine loudness to zombies. Min: 0.00 Max: 100.00 Default: 1.00 + ZombieAttractionMultiplier = 1.0, + -- Whether found vehicles are locked, need keys to start etc. + VehicleEasyUse = false, + -- How full the gas tank of discovered vehicles will be. Default = Low + -- 1 = Very Low + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + -- 6 = Full + InitialGas = 2, + -- If enabled, gas pumps will never run out of fuel + FuelStationGasInfinite = false, + -- The minimum amount of gasoline that can spawn in gas pumps. Check the "Advanced" box below to use a custom amount. Min: 0.00 Max: 1.00 Default: 0.00 + FuelStationGasMin = 0.0, + -- The maximum amount of gasoline that can spawn in gas pumps. Check the "Advanced" box below to use a custom amount. Min: 0.00 Max: 1.00 Default: 0.80 + FuelStationGasMax = 0.8, + -- The chance, as a percentage, that individual gas pumps will initially have no fuel. Min: 0 Max: 100 Default: 20 + FuelStationGasEmptyChance = 20, + -- How likely cars will be locked Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + LockedCar = 4, + -- How gas-hungry vehicles are. Min: 0.00 Max: 100.00 Default: 1.00 + CarGasConsumption = 0.8, + -- General condition discovered vehicles will be in. Default = Normal + -- 1 = Very Low + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + CarGeneralCondition = 2, + -- The amount of damage dealt to vehicles that crash. Default = Normal + -- 1 = Very Low + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + CarDamageOnImpact = 3, + -- Damage received by the player from being crashed into. Default = None + -- 1 = None + -- 2 = Low + -- 3 = Normal + -- 4 = High + -- 5 = Very High + DamageToPlayerFromHitByACar = 1, + -- If traffic jams consisting of wrecked cars will appear on main roads. + TrafficJam = true, + -- How frequently discovered vehicles have active alarms. Default = Rare + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + CarAlarm = 3, + -- If the player can get injured from being in a car accident. + PlayerDamageFromCrash = true, + -- How many in-game hours before a wailing siren shuts off. Min: 0.00 Max: 168.00 Default: 0.00 + SirenShutoffHours = 0.0, + -- The chance of finding a vehicle with gas in its tank. Default = Normal + -- 1 = Low + -- 2 = Normal + -- 3 = High + ChanceHasGas = 1, + -- Whether a player can discover a car that has been cared for after the Knox infection struck. Default = Low + -- 1 = None + -- 2 = Low + -- 3 = Normal + -- 4 = High + RecentlySurvivorVehicles = 1, + -- If certain melee weapons will be able to strike multiple zombies in one hit. + MultiHitZombies = false, + -- Chance of being bitten when a zombie attacks from behind. Default = High + -- 1 = Low + -- 2 = Medium + -- 3 = High + RearVulnerability = 3, + -- If zombies will head towards the sound of vehicle sirens. + SirenEffectsZombies = true, + -- Speed at which animals stats (hunger, thirst etc.) reduce. Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalStatsModifier = 4, + -- Speed at which animals stats (hunger, thirst etc.) reduce while in meta. Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalMetaStatsModifier = 4, + -- How long animals will be pregnant for before giving birth. Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalPregnancyTime = 4, + -- Speed at which animals age. Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalAgeModifier = 4, + -- Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalMilkIncModifier = 4, + -- Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalWoolIncModifier = 4, + -- The chance of finding animals in farm. Default = Often + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always + AnimalRanchChance = 5, + -- The number of hours grass will regrow after being eaten by an animal or cut by the player. Min: 1 Max: 9999 Default: 240 + AnimalGrassRegrowTime = 240, + -- If a meta (ie. not actually visible in-game) fox may attack your chickens if the hutch's door is left open at night. + AnimalMetaPredator = false, + -- If on, animals will only mate during their breeding season (if any). Otherwise they can reproduce/lay eggs all year round. + AnimalMatingSeason = true, + -- How long before baby animals will hatch from eggs. Default = Normal + -- 1 = Ultra Fast + -- 2 = Very Fast + -- 3 = Fast + -- 4 = Normal + -- 5 = Slow + -- 6 = Very Slow + AnimalEggHatch = 4, + -- If true, animal calls will attract nearby zombies. + AnimalSoundAttractZombies = true, + -- The chance of animals leaving tracks. Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + AnimalTrackChance = 4, + -- The chance of creating a path for animals to be hunted. Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + AnimalPathChance = 4, + -- The frequency and intensity of eg. rats in infested buildings. Min: 0 Max: 50 Default: 25 + MaximumRatIndex = 25, + -- How long it takes for the Maximum Vermin Index to be reached. Min: 0 Max: 365 Default: 90 + DaysUntilMaximumRatIndex = 90, + -- If a piece of media hasn't been fully seen or read, this setting determines whether it's displayed fully, displayed as "???", or hidden completely. Default = Completely hidden + -- 1 = Fully revealed + -- 2 = Shown as ??? + -- 3 = Completely hidden + MetaKnowledge = 3, + -- If true, you will be able to see any recipes that can be done with a station, even if you haven't learnt them yet. + SeeNotLearntRecipe = true, + -- If a building has more than this amount of rooms it will not be looted. Min: 0 Max: 200 Default: 50 + MaximumLootedBuildingRooms = 50, + -- If poison can be added to food. Default = True + -- 1 = True + -- 2 = False + -- 3 = Only bleach poisoning is disabled + EnablePoisoning = 1, + -- If/when maggots can spawn in corpses. Default = In and Around Bodies + -- 1 = In and Around Bodies + -- 2 = In Bodies Only + -- 3 = Never + MaggotSpawn = 2, + -- The higher the value, the longer lightbulbs last before breaking. If 0, lightbulbs will never break. Does not affect vehicle headlights. Min: 0.00 Max: 1000.00 Default: 2.00 + LightBulbLifespan = 2.0, + -- The abundance of fish in rivers and lakes. Default = Poor + -- 1 = Very Poor + -- 2 = Poor + -- 3 = Normal + -- 4 = Abundant + -- 5 = Very Abundant + FishAbundance = 2, + -- When a skill is at this level or above, television/VHS/other media will not provide XP for it. Min: 0 Max: 10 Default: 3 + LevelForMediaXPCutoff = 3, + -- When a skill is at this level or above, scrapping furniture does not provide XP for the relevant skill. Does not apply to Electrical. Min: 0 Max: 10 Default: 0 + LevelForDismantleXPCutoff = 0, + -- Number of days before old blood splats are removed. Removal happens when map chunks are loaded. 0 means they will never disappear. Min: 0 Max: 365 Default: 0 + BloodSplatLifespanDays = 14, + -- Number of days before one can benefit from reading previously read literature items. Min: 1 Max: 365 Default: 45 + LiteratureCooldown = 45, + -- If there are diminishing returns on bonus trait points provided from selecting multiple negative traits. Default = None + -- 1 = None + -- 2 = 1 point penalty for every 3 negative traits selected + -- 3 = 1 point penalty for every 2 negative traits selected + -- 4 = 1 point penalty for every negative trait selected after the first + NegativeTraitsPenalty = 1, + -- The number of in-game minutes it takes to read one page of a skill book. Min: 0.00 Max: 60.00 Default: 2.00 + MinutesPerPage = 2.0, + -- When enabled, crops and herbs grown inside buildings will die. Does not affect houseplants. + KillInsideCrops = true, + -- When enabled, the growth of plants is affected by seasons. + PlantGrowingSeasons = true, + -- [!] It is recommended that you DO NOT change this. Changing this can result in performance issues. [!] When enabled, dirt can be placed, and farming performed on other than the ground level. + PlaceDirtAboveground = false, + -- The speed of plant growth. Min: 0.10 Max: 100.00 Default: 1.00 + FarmingSpeedNew = 1.0, + -- The abundance of harvested crops. Min: 0.10 Max: 10.00 Default: 1.00 + FarmingAmountNew = 1.0, + -- The chance that any building will already be looted when found. Check the "Advanced" box below to use a custom number. Min: 0 Max: 200 Default: 25 + MaximumLooted = 25, + -- How long it takes for Maximum Looted Building Chance to be reached. Min: 0 Max: 3650 Default: 90 + DaysUntilMaximumLooted = 90, + -- The chance that any rural building will already be looted when found. Check the "Advanced" box below to use a custom number. Min: 0.00 Max: 2.00 Default: 0.50 + RuralLooted = 0.5, + -- The maximum loot that won't spawn when Days Until Maximum Diminished Loot is reached. Check the "Advanced" box below to use an exact percentage. Min: 0 Max: 100 Default: 20 + MaximumDiminishedLoot = 20, + -- How long it takes for Maximum Diminished Loot Percentage to be reached. Min: 0 Max: 3650 Default: 3650 + DaysUntilMaximumDiminishedLoot = 3650, + -- Functions as a multiplier when applying muscle strain from swinging weapons or carrying heavy loads. Min: 0.00 Max: 10.00 Default: 0.70 + MuscleStrainFactor = 0.7, + -- Functions as a multiplier when applying discomfort from worn items. Min: 0.00 Max: 10.00 Default: 0.80 + DiscomfortFactor = 0.8, + -- If greater than zero damage can be taken from serious wound infections. Min: 0.00 Max: 10.00 Default: 1.00 + WoundInfectionFactor = 1.0, + -- If true clothing with randomized tints will not be so dark to be virtually black. + NoBlackClothes = true, + -- Disables the failure chances when climbing sheet ropes or over walls. + EasyClimbing = false, + -- The maximum hours of fuel that can be placed in a campfire, wood stove etc. Min: 1 Max: 168 Default: 8 + MaximumFireFuelHours = 8, + -- Replaces Chance-To-Hit mechanics with Chance-To-Damage calculations. This mode prioritizes player aiming. Default = Zombies only + -- 1 = Disabled + -- 2 = Zombies only + -- 3 = All types of target + FirearmUseDamageChance = 2, + -- A multiplier for the distance at which zombies can hear gunshots. Min: 0.20 Max: 2.00 Default: 1.00 + FirearmNoiseMultiplier = 1.0, + -- Multiplier for firearm jamming chance. 0 disables jamming. Min: 0.00 Max: 10.00 Default: 1.00 + FirearmJamMultiplier = 1.0, + -- Multiplier for Moodle effects on hit chance. 0 disables Moodle penalty. Min: 0.00 Max: 10.00 Default: 1.00 + FirearmMoodleMultiplier = 1.0, + -- Multiplier for the effects of weather (wind, rain and fog) on hit chance. 0 disables weather effect. Min: 0.00 Max: 10.00 Default: 1.00 + FirearmWeatherMultiplier = 1.0, + -- Enable to have headgear like welding masks affect hit chance + FirearmHeadGearEffect = true, + -- Chance to turn a dirt floor into a clay floor. Applies to lakes. Min: 0.00 Max: 1.00 Default: 0.05 + ClayLakeChance = 0.05, + -- Chance to turn a dirt floor into a clay floor. Applies to rivers. Min: 0.00 Max: 1.00 Default: 0.05 + ClayRiverChance = 0.05, + -- Min: 1 Max: 100 Default: 20 + GeneratorTileRange = 20, + -- How many levels both above and below a generator it can provide with electricity. Min: 1 Max: 15 Default: 3 + GeneratorVerticalPowerRange = 3, + -- Min: -1 Max: 100 Default: -1 + BAM_Server_MinSuccessChance = -1, + -- Min: 0.00 Max: 50.00 Default: 0.02 + MeatGrinderLootDrop = 0.02, + VRO_EnableEngineRebuild = false, + VRO_UseVanillaFixingRecipes = false, + VRO_EnableFullVehicleSalvaging = true, + Basement = { + -- How frequently basements spawn at random locations. Default = Sometimes + -- 1 = Never + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always + SpawnFrequency = 4, + }, + Map = { + -- If enabled, a mini-map window will be available. + AllowMiniMap = true, + -- If enabled, the world map can be accessed. + AllowWorldMap = true, + -- If enabled, the world map will be completely filled in on starting the game. + MapAllKnown = true, + -- If enabled, maps can't be read unless there's a source of light available. + MapNeedsLight = true, + }, + ZombieLore = { + -- How fast zombies move. Default = Random + -- 1 = Sprinters + -- 2 = Fast Shamblers + -- 3 = Shamblers + -- 4 = Random + Speed = 4, + -- If Random Speed is enabled, this controls what percentage of zombies are Sprinters. Check the "Advanced" box below to use a custom percentage. Min: 0 Max: 100 Default: 0 + SprinterPercentage = 1, + -- The damage zombies inflict per attack. Default = Normal + -- 1 = Superhuman + -- 2 = Normal + -- 3 = Weak + -- 4 = Random + Strength = 2, + -- The difficulty of killing a zombie. Default = Random + -- 1 = Tough + -- 2 = Normal + -- 3 = Fragile + -- 4 = Random + Toughness = 4, + -- How the Knox Virus spreads. Default = Blood and Saliva + -- 1 = Blood and Saliva + -- 2 = Saliva Only + -- 3 = Everyone's Infected + -- 4 = None + Transmission = 1, + -- How quickly the infection takes effect. Default = 2-3 Days + -- 1 = Instant + -- 2 = 0-30 Seconds + -- 3 = 0-1 Minutes + -- 4 = 0-12 Hours + -- 5 = 2-3 Days + -- 6 = 1-2 Weeks + -- 7 = Never + Mortality = 5, + -- How quickly infected corpses rise as zombies. Default = 0-1 Minutes + -- 1 = Instant + -- 2 = 0-30 Seconds + -- 3 = 0-1 Minutes + -- 4 = 0-12 Hours + -- 5 = 2-3 Days + -- 6 = 1-2 Weeks + Reanimate = 3, + -- Zombie intelligence. Default = Basic Navigation + -- 1 = Navigate and Use Doors + -- 2 = Navigate + -- 3 = Basic Navigation + -- 4 = Random + Cognition = 3, + -- Min: 0 Max: 100 Default: 0 + DoorOpeningPercentage = 0, + -- How often zombies can crawl under parked vehicles. Default = Often + -- 1 = Crawlers Only + -- 2 = Extremely Rare + -- 3 = Rare + -- 4 = Sometimes + -- 5 = Often + -- 6 = Very Often + -- 7 = Always + CrawlUnderVehicle = 5, + -- How long zombies remember a player after seeing or hearing them. Default = Normal + -- 1 = Long + -- 2 = Normal + -- 3 = Short + -- 4 = None + -- 5 = Random + -- 6 = Random between Normal and None + Memory = 2, + -- Zombie vision radius. Default = Random between Normal and Poor + -- 1 = Eagle + -- 2 = Normal + -- 3 = Poor + -- 4 = Random + -- 5 = Random between Normal and Poor + Sight = 5, + -- Zombie hearing radius. Default = Random between Normal and Poor + -- 1 = Pinpoint + -- 2 = Normal + -- 3 = Poor + -- 4 = Random + -- 5 = Random between Normal and Poor + Hearing = 5, + -- Activates the new advanced stealth mechanics, which allows you to hide from zombies behind cars, takes traits and weather into account, and much more. + SpottedLogic = true, + -- If zombies that have not seen/heard player can attack doors and constructions while roaming. + ThumpNoChasing = false, + -- If zombies can destroy player constructions and defenses. + ThumpOnConstruction = true, + -- Whether zombies are more "active" during the day or night. "Active" zombies will use the speed set in the "Speed" setting. "Inactive" zombies will be slower, and tend not to give chase. Default = Both + -- 1 = Both + -- 2 = Night + -- 3 = Day + ActiveOnly = 1, + -- If zombies trigger house alarms when breaking through windows or doors. + TriggerHouseAlarm = true, + -- If multiple attacking zombies can drag you down and kill you. Dependent on zombie strength. + ZombiesDragDown = true, + -- If crawler zombies beside a player contribute to the chance of being dragged down and killed by a group of zombies. + ZombiesCrawlersDragDown = false, + -- If zombies have a chance to lunge at you after climbing over a fence or through a window if you're too close. + ZombiesFenceLunge = true, + -- Serves as a multiplier when determining the effectiveness of armor worn by zombies. Min: 0.00 Max: 100.00 Default: 2.00 + ZombiesArmorFactor = 2.0, + -- The maximum defense percentage that any worn protective garments can provide to a zombie. Min: 0 Max: 100 Default: 85 + ZombiesMaxDefense = 85, + -- Percentage chance of having a random attached weapon. Min: 0 Max: 100 Default: 6 + ChanceOfAttachedWeapon = 6, + -- How much damage zombies take when falling from height. Min: 0.00 Max: 100.00 Default: 1.00 + ZombiesFallDamage = 1.0, + -- Whether some dead-looking zombies will reanimate and attack the player. Default = World Zombies + -- 1 = World Zombies + -- 2 = World and Combat Zombies + -- 3 = Never + DisableFakeDead = 1, + -- Zombies will not spawn where players spawn. Default = Inside the building and around it + -- 1 = Inside the building and around it + -- 2 = Inside the building + -- 3 = Inside the room + -- 4 = Zombies can spawn anywhere + PlayerSpawnZombieRemoval = 1, + -- How many zombies it takes to damage a tall fence. Min: -1 Max: 100 Default: 25 + FenceThumpersRequired = 25, + -- How quickly zombies damage tall fences. Min: 0.01 Max: 100.00 Default: 1.00 + FenceDamageMultiplier = 1.0, + }, + ZombieConfig = { + -- Set by the "Zombie Count" population option, or by a custom number here. Insane = 2.5, Very High = 1.6, High = 1.2, Normal = 0.65, Low = 0.15, None = 0.0. Min: 0.00 Max: 4.00 Default: 0.65 + PopulationMultiplier = 0.75, + -- A multiplier for the desired zombie population at the start of the game. Insane = 3.0, Very High = 2.0, High = 1.5, Normal = 1.0, Low = 0.5, None = 0.0. Min: 0.00 Max: 4.00 Default: 1.00 + PopulationStartMultiplier = 1.1, + -- A multiplier for the desired zombie population on the peak day. Insane = 3.0, Very High = 2.0, High = 1.5, Normal = 1.0, Low = 0.5, None = 0.0. Min: 0.00 Max: 4.00 Default: 1.50 + PopulationPeakMultiplier = 1.8, + -- The day when the population reaches its peak. Min: 1 Max: 365 Default: 28 + PopulationPeakDay = 28, + -- The number of hours that must pass before zombies may respawn in a cell. If 0, spawning is disabled. Min: 0.00 Max: 8760.00 Default: 0.00 + RespawnHours = 0.0, + -- The number of hours that a chunk must be unseen before zombies may respawn in it. Min: 0.00 Max: 8760.00 Default: 0.00 + RespawnUnseenHours = 0.0, + -- The fraction of a cell's desired population that may respawn every RespawnHours. Min: 0.00 Max: 1.00 Default: 0.00 + RespawnMultiplier = 0.0, + -- The number of hours that must pass before zombies migrate to empty parts of the same cell. If 0, migration is disabled. Min: 0.00 Max: 8760.00 Default: 12.00 + RedistributeHours = 12.0, + -- The distance a zombie will try to walk towards the last sound it heard. Min: 10 Max: 1000 Default: 100 + FollowSoundDistance = 100, + -- The size of groups real zombies form when idle. 0 means zombies don't form groups. Groups don't form inside buildings or forest zones. Min: 0 Max: 1000 Default: 20 + RallyGroupSize = 15, + -- The amount, as a percentage, that zombie groups can vary in size from the default (both larger and smaller). For example, at 50% variance with a default group size of 20, groups will vary in size from 10-30. Min: 0 Max: 100 Default: 50 + RallyGroupSizeVariance = 50, + -- The distance real zombies travel to form groups when idle. Min: 5 Max: 50 Default: 20 + RallyTravelDistance = 20, + -- The distance between zombie groups. Min: 5 Max: 25 Default: 15 + RallyGroupSeparation = 15, + -- How close members of a zombie group stay to the group's "leader". Min: 1 Max: 10 Default: 3 + RallyGroupRadius = 3, + -- Controls the maximum number of zombies tracked before cleanup occurs. 0 means zombies will not be cleaned up. The default value (300) is strongly recommended. Increasing this value or setting to 0 may cause severe performance problems. For troubleshooting and bug-report purposes, please reproduce any issue with the default setting before submitting a report. Min: 0 Max: 5000 Default: 300 + ZombiesCountBeforeDelete = 300, + }, + MultiplierConfig = { + -- The rate at which all skills level up. Min: 0.00 Max: 1000.00 Default: 1.00 + Global = 1.0, + -- When enabled, all skills will use the Global Multiplier. + GlobalToggle = true, + -- Rate at which Fitness skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Fitness = 1.0, + -- Rate at which Strength skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Strength = 1.0, + -- Rate at which Sprinting skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Sprinting = 1.0, + -- Rate at which Lightfooted skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Lightfoot = 1.0, + -- Rate at which Nimble skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Nimble = 1.0, + -- Rate at which Sneaking skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Sneak = 1.0, + -- Rate at which Axe skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Axe = 1.0, + -- Rate at which Long Blunt skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Blunt = 1.0, + -- Rate at which Short Blunt skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + SmallBlunt = 1.0, + -- Rate at which Long Blade skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + LongBlade = 1.0, + -- Rate at which Short Blade skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + SmallBlade = 1.0, + -- Rate at which Spear skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Spear = 1.0, + -- Rate at which Maintenance skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Maintenance = 1.0, + -- Rate at which Carpentry skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Woodwork = 1.0, + -- Rate at which Cooking skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Cooking = 1.0, + -- Rate at which Agriculture skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Farming = 1.0, + -- Rate at which First Aid skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Doctor = 1.0, + -- Rate at which Electrical skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Electricity = 1.0, + -- Rate at which Welding skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + MetalWelding = 1.0, + -- Rate at which Mechanics skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Mechanics = 1.0, + -- Rate at which Tailoring skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Tailoring = 1.0, + -- Rate at which Aiming skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Aiming = 1.0, + -- Rate at which Reloading skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Reloading = 1.0, + -- Rate at which Fishing skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Fishing = 1.0, + -- Rate at which Trapping skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Trapping = 1.0, + -- Rate at which Foraging skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + PlantScavenging = 1.0, + -- Rate at which Knapping skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + FlintKnapping = 1.0, + -- Rate at which Masonry skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Masonry = 1.0, + -- Rate at which Pottery skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Pottery = 1.0, + -- Rate at which Carving skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Carving = 1.0, + -- Rate at which Animal Care skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Husbandry = 1.0, + -- Rate at which Tracking skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Tracking = 1.0, + -- Rate at which Blacksmithing skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Blacksmith = 1.0, + -- Rate at which Butchering skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Butchering = 1.0, + -- Rate at which Glassmaking skill levels up. Min: 0.00 Max: 1000.00 Default: 1.00 + Glassmaking = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + Art = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + Cleaning = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + Dancing = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + Meditation = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + Music = 1.0, + }, + HB = { + PermanentCasings = true, + -- Min: 0 Max: 5 Default: 0 + MultiplayerTick = 0, + CustomIcons = true, + CasingSounds = true, + }, + RVAddon = { + CustomNormalVehicles = "", + CustomBusVehicles = "", + CustomSmallVehicles = "", + Custom3x2Caravan = "", + Custom3x6Caravan = "", + Custom3x7Empty = "", + Custom4x12colossal = "", + }, + MHP = { + EnableReplaceBandage = true, + ShowSafeRemoveIndicator = false, + ShowStitchInspectIndicator = false, + }, + SPNCharCustom = { + AllowCustomisationChange = 4, + AdminLockedCustomisation = "", + -- Min: 0 Max: 20 Default: 10 + BodyHairGrowth = 10, + -- Min: 0 Max: 20 Default: 6 + StubbleHeadGrowth = 6, + -- Min: 0 Max: 20 Default: 3 + StubbleBeardGrowth = 3, + BodyHairGrowthEnabled = 1, + MuscleVisuals = 1, + -- Min: 0.10 Max: 1.00 Default: 0.50 + MissingEyeVisionModifier = 0.5, + WashMakeup = true, + }, + SandboxOptions = { + EnableRightClick = true, + ShowAdvanced = true, + }, + SOTO = { + AddFitXPWhileRun = true, + AgilityTraitsObtainable = true, + CombatTraitsObtainable = true, + SurvTraitsObtainable = false, + CraftTraitsObtainable = false, + FirearmTraitsObtainable = true, + CowardlyRemovable = true, + -- Min: 1 Max: 100000 Default: 168 + CowardlyHoursToRemoveMin = 168, + -- Min: 1 Max: 100000 Default: 336 + CowardlyHoursToRemoveMax = 336, + -- Min: 1 Max: 100000 Default: 1250 + CowardlyZombiesKilledToRemoveMin = 1000, + -- Min: 1 Max: 100000 Default: 2500 + CowardlyZombiesKilledToRemoveMax = 2000, + BraveEarnable = true, + -- Min: 1 Max: 100000 Default: 504 + BraveHoursToEarnMin = 504, + -- Min: 1 Max: 100000 Default: 840 + BraveHoursToEarnMax = 840, + -- Min: 1 Max: 100000 Default: 3000 + BraveZombiesKilledToEarnMin = 2500, + -- Min: 1 Max: 100000 Default: 4500 + BraveZombiesKilledToEarnMax = 4000, + DesensitizedEarnable = true, + -- Min: 1 Max: 100000 Default: 1176 + DesensitizedHoursToEarnMin = 1176, + -- Min: 1 Max: 100000 Default: 1512 + DesensitizedHoursToEarnMax = 1512, + -- Min: 1 Max: 100000 Default: 6000 + DesensitizedZombiesKilledToEarnMin = 5000, + -- Min: 1 Max: 100000 Default: 9000 + DesensitizedZombiesKilledToEarnMax = 7000, + PacifistRemovable = true, + -- Min: 1 Max: 100000 Default: 672 + PacifistHoursToRemoveMin = 672, + -- Min: 1 Max: 100000 Default: 1008 + PacifistHoursToRemoveMax = 1008, + -- Min: 1 Max: 100000 Default: 1500 + PacifistZombiesKilledToRemoveMin = 1500, + -- Min: 1 Max: 100000 Default: 2500 + PacifistZombiesKilledToRemoveMax = 2500, + -- Min: 0 Max: 10 Default: 7 + PacifistSkillLvlToRemove = 7, + SmokerRemovable = true, + -- Min: 1 Max: 100000 Default: 672 + SmokerHoursToRemoveMin = 672, + -- Min: 1 Max: 100000 Default: 768 + SmokerHoursToRemoveMax = 768, + AlcoholicRemovable = true, + -- Min: 1 Max: 100000 Default: 1032 + AlcoholicHoursToRemoveMin = 1032, + -- Min: 1 Max: 100000 Default: 1128 + AlcoholicHoursToRemoveMax = 1128, + SundayDriverRemovable = true, + -- Min: 1 Max: 100000 Default: 60 + SundayDriverHoursToRemoveMin = 60, + -- Min: 1 Max: 100000 Default: 80 + SundayDriverHoursToRemoveMax = 80, + AllThumbsRemovable = true, + -- Min: 1 Max: 100000 Default: 37500 + AllThumbsValueToRemove = 37500, + DisorganizedRemovable = true, + -- Min: 1 Max: 100000 Default: 37500 + DisorganizedValueToRemove = 37500, + GracefulEarnable = true, + ClumsyRemovable = true, + InconspicuousEarnable = true, + ConspicuousRemovable = true, + }, + WorkingKnowledge = { + SpawnRate = 2, + -- Min: 0 Max: 500 Default: 50 + XPGrant = 50, + }, + SkillRecoveryJournal = { + -- Min: 1 Max: 100 Default: 100 + RecoveryPercentage = 70, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + TranscribeSpeed = 1.0, + -- Min: 0.00 Max: 1000.00 Default: 1.00 + ReadTimeSpeed = 1.0, + RecoverProfessionAndTraitsBonuses = false, + TranscribeTVXP = false, + -- Min: -1 Max: 100 Default: 0 + RecoverPassiveSkills = 0, + -- Min: -1 Max: 100 Default: -1 + RecoverPhysicalCategorySkills = -1, + -- Min: -1 Max: 100 Default: -1 + RecoverCombatSkills = -1, + -- Min: -1 Max: 100 Default: -1 + RecoverFirearmSkills = -1, + -- Min: -1 Max: 100 Default: -1 + RecoverCraftingSkills = -1, + -- Min: -1 Max: 100 Default: -1 + RecoverSurvivalistSkills = -1, + -- Min: -1 Max: 100 Default: -1 + RecoverFarmingCategorySkills = -1, + -- Min: -1 Max: 100 Default: 0 + KillsTrack = 0, + RecoverRecipes = true, + RecoveryJournalUsed = false, + SecurityFeatures = 1, + CraftRecipeNeedLearn = false, + CraftRecipe = "", + ModDataTrack = "", + }, + M13ReadingTweaks = { + RWW = true, + -- Min: 0.01 Max: 100.00 Default: 2.00 + PSM = 2.5, + }, + KillCount = { + doExport = false, + includePostDeathUI = true, + -- Min: 0 Max: 10000000 Default: 500 + MaxUpdateDelay = 500, + shareOnServer = true, + keepTrackOfDead = true, + }, + DAMN = { + AllowPowerChadSpawns = false, + AllowPro440Spawns = false, + AllowDemonChildSpawns = false, + AllowEV6spawns = false, + AllowTBCspawns = false, + AllowUBCspawns = false, + AllowWreckyMcChevySpawns = false, + AllowShitSpawns = false, + AllowManlyMANSpawns = false, + AllowGreatScottSpawns = false, + AllowOinkerSpawns = false, + AllowMrBusSpawns = false, + AllowChonkerSpawns = false, + AllowCashcowSpawns = false, + AllowMcBoxySpawns = false, + AllowSuckyMcSuckfaceSpawns = false, + }, + CF8KSweeper = { + AllowTiles = true, + SpriteWhitelist = "brokenglass_1_;trash_01_;d_trash_;street_decoration_01_26;street_decoration_01_27;damaged_objects_01_26;damaged_objects_01_27;damaged_objects_01_18;damaged_objects_01_19;damaged_objects_01_20;damaged_objects_01_21", + AllowBlood = true, + AllowGrime = true, + AllowAshes = true, + AllowItems = true, + AllowCorpses = true, + AllowUserAutoDelete = false, + }, + ReactiveSE = { + -- Min: 1 Max: 720 Default: 48 + MinEventCooldown = 48, + -- Min: 2 Max: 720 Default: 240 + MaxEventCooldown = 240, + -- Min: 1 Max: 20 Default: 4 + EventChance = 4, + FlatProbability = true, + -- Min: 120 Max: 1000 Default: 200 + MinSoundRange = 200, + -- Min: 120 Max: 1000 Default: 600 + MaxSoundRange = 600, + -- Min: 120 Max: 1000 Default: 300 + ReactionThresholdRange = 300, + -- Min: 0 Max: 100 Default: 20 + CloseDistanceChance = 20, + -- Min: 0 Max: 100 Default: 40 + MediumDistanceChance = 40, + -- Min: 0 Max: 100 Default: 40 + FarDistanceChance = 40, + EnableZombieHearing = true, + EnableDebugMode = false, + }, + ReactiveSEEvents = { + EnableAnimalEvents = true, + EnableGunfightEvents = true, + EnableGunshotEvents = true, + EnableScreamEvents = true, + EnableVehicleCrashEvents = true, + EnableWeatherEvents = true, + EnableZombieEvents = true, + }, + ReactiveSEBehavior = { + EnablePlayerStyle = true, + -- Min: 10 Max: 200 Default: 40 + AggressiveStyleKills = 40, + -- Min: 1 Max: 7 Default: 2 + PassiveStyleDays = 2, + EnablePlayerReactionPanic = true, + EnablePlayerReactionWakeUp = true, + }, + ReactiveSEScenes = { + EnableEventScenes = true, + -- Min: 0 Max: 100 Default: 100 + EventSceneChance = 100, + -- Min: 0 Max: 168 Default: 72 + SceneCleanupHours = 72, + EnableGunfightScene = true, + EnableGunshotScene = true, + EnableScreamScene = true, + -- Min: 0 Max: 10 Default: 3 + ScreamZombieCount = 3, + EnableVehicleCrashScene = true, + VehicleMaxCondition = 2, + -- Min: 0 Max: 100 Default: 25 + VehicleKeyChance = 25, + EnableZombieScene = true, + -- Min: 1 Max: 20 Default: 8 + ZombieSceneMin = 8, + -- Min: 1 Max: 20 Default: 16 + ZombieSceneMax = 16, + EnableSceneSpawnNotify = true, + SceneSpawnNotifyText = true, + SceneSpawnNotifyMarker = true, + }, + ReactiveSELoot = { + LootQuality = 1, + -- Min: 10 Max: 100 Default: 100 + WeaponMaxCondition = 100, + -- Min: 0 Max: 100 Default: 10 + RangedWeaponChance = 10, + -- Min: 0 Max: 100 Default: 0 + MinBackpackStealChance = 0, + -- Min: 0 Max: 100 Default: 70 + MaxBackpackStealChance = 70, + AmmoScarcity = 2, + -- Min: 1 Max: 10 Default: 1 + SubKitCountMin = 1, + -- Min: 1 Max: 10 Default: 3 + SubKitCountMax = 3, + }, + ReactiveSEWorld = { + -- Min: 2 Max: 8 Default: 3 + CorpseCount = 3, + -- Min: 1 Max: 365 Default: 7 + WorldTierEarlyEnd = 7, + -- Min: 2 Max: 365 Default: 30 + WorldTierMidEnd = 30, + -- Min: 3 Max: 365 Default: 90 + WorldTierLateEnd = 90, + }, + ReactiveSERadio = { + EnableRadioFeature = true, + EnableMapMarker = true, + EnableMorningShowXP = true, + }, + HereGoesTheSun = { + EnableGodRays = false, + EnableStormMood = true, + StormMoodPreset = 2, + }, + RainCleansBlood = { + -- Min: 1 Max: 60 Default: 10 + TilesPerMinute = 10, + -- Min: 0.05 Max: 0.95 Default: 0.25 + WeatherThreshold = 0.25, + AlsoCleanAsh = true, + AlsoCleanInside = false, + AlsoCleanVehicles = true, + -- Min: 0.10 Max: 1.00 Default: 0.10 + VehicleCleanSpeed = 0.1, + AlsoCleanClothes = true, + -- Min: 1.00 Max: 10.00 Default: 1.00 + ClothesCleanSpeed = 1.0, + AlwaysClean = false, + }, + DeadMansDossier = { + DropChance_Police = 3, + DropChance_Military = 2, + DropChance_Medical = 3, + DropChance_Firefighter = 3, + DropChance_Ranger = 3, + ContainerSpawnRate = 3, + RewardRarity = 2, + -- Min: 5 Max: 50 Default: 15 + ProximityRadius = 15, + UseCustomRewards = false, + }, + KnoxDetectionKit = { + KitRarity = 4, + -- Min: 0 Max: 1440 Default: 120 + WaitMinutes = 120, + }, + ZombieVirusVaccineBETA = { + DebugMode = false, + EnableWorldLoot = true, + LootChemicals = 3, + ExpandChemicalsLoot = false, + EnableVehicleLoot = true, + EnableBagsLoot = true, + LootSyringes = 3, + LootEquipmentBooks = 3, + LootVirologyBooks = 3, + VirologyBooksSpawnMode = 2, + BloodAgingMode = true, + -- Min: 5 Max: 21 Default: 14 + BloodAgingRadius = 14, + EnableWaterPurification = true, + -- Min: 5 Max: 21 Default: 5 + WaterPurificationRadius = 5, + EnableLightPaints = true, + AllowWindowGlass = true, + AllowAutopsyOnGround = true, + -- Min: 800 Max: 1800 Default: 1200 + AutopsySpeed = 1200, + -- Min: 2 Max: 72 Default: 12 + AutopsyMaxHours = 12, + -- Min: 0 Max: 30 Default: 30 + TicksDecreasedByPerkLv = 30, + TableSpeedBonus = 6, + -- Min: 0 Max: 15 Default: 15 + AutopsyGroundXP = 15, + -- Min: 0 Max: 30 Default: 30 + AutopsyTableXP = 30, + -- Min: 0 Max: 30 Default: 15 + CollectPartXP = 15, + -- Min: 0 Max: 15 Default: 10 + BrainHighOffset = 10, + -- Min: 0 Max: 30 Default: 10 + HemophobicDebuff = 10, + AllowScalpelDegrade = false, + AllowSawDegrade = true, + }, + Text = { + DividerMusicNew = true, + DividerDancingNew = true, + DividerMeditationNew = true, + DividerHygiene = true, + DividerArt = true, + LSDividerOther = false, + DividerDebug = false, + }, + LSAmbt = { + Toggle = true, + -- Min: 1 Max: 1000 Default: 36 + Cooldown = 36, + -- Min: 1 Max: 100 Default: 1 + MaxInProgress = 1, + -- Min: 1 Max: 100 Default: 3 + MaxTotal = 3, + ResetException = false, + HideTips = false, + }, + Music = { + StrengthMultiplier = 2, + ListeningStrengthMultiplier = 2, + LearningChance = 3, + Metabolics = 1, + }, + Dancing = { + StrengthMultiplier = 2, + }, + Meditation = { + StrengthMultiplier = 2, + MindfulnessDuration = 2, + -- Min: 0.00 Max: 10.00 Default: 2.00 + HealFactor = 2.0, + EffectMultiplier = 2, + KeepBags = false, + }, + LSMeditation = { + RemoveLevitation = true, + }, + Yoga = { + StrengthMultiplier = 2, + Exhaustion = 3, + Embarrassment = 2, + AidObjects = true, + RequiresMat = false, + KeepBags = false, + FailChance = 4, + -- Min: 0.10 Max: 5.00 Default: 1.00 + YogaXPMultiplier = 1.0, + -- Min: 0.10 Max: 5.00 Default: 1.00 + FitnessXPMultiplier = 1.0, + -- Min: 0.10 Max: 5.00 Default: 1.00 + NimbleXPMultiplier = 1.0, + }, + LSHygiene = { + -- Min: 0.00 Max: 3.00 Default: 1.00 + HygieneNeedMultiplier = 1.0, + -- Min: 0.00 Max: 3.00 Default: 1.00 + BladderNeedMultiplier = 0.0, + HygieneNeedExpectationTime = 2, + CleansMakeup = true, + NotEmbarrassed = false, + ColdSeverity = 2, + -- Min: 0.00 Max: 3.00 Default: 0.00 + ColdChanceMultiplier = 0.0, + -- Min: 1 Max: 100 Default: 10 + OuthouseRange = 10, + CleaningExpectationTime = 2, + CleaningLitterChance = 3, + }, + LSArt = { + -- Min: 0.10 Max: 3.00 Default: 1.00 + GeneralBeautyMultiplier = 1.0, + BeautyOutdoors = false, + BeautyShowNegative = false, + BeautyNeedDecayRate = 3, + BeautyNeedStrength = 3, + -- Min: 0.10 Max: 4.00 Default: 1.00 + ArtworkBeautyMultiplier = 1.0, + }, + LS = { + DynamicTraits = false, + DynamicTraitsReverse = 1, + DividerServer = false, + ModdataUpdate = 1, + MoodUpdate = 1, + }, + LSComfort = { + -- Min: 0.00 Max: 3.00 Default: 1.00 + ComfortNeedMultiplier = 1.0, + ComfortPositive = false, + ComfortNoImpact = false, + }, + Debug = { + MoodlePriority = false, + Expressions = false, + DanceAnim = false, + LSVerbose = false, + }, + GydeTraitMags = { + NegativeToPositive = false, + ReadRemove = false, + ReadDelete = false, + -- Min: 0 Max: 8766 Default: 0 + DaysBeforeRead = 0, + SpawnRate = 2, + SpawnSpeedDemon = true, + SpawnNutritionist = true, + SpawnOrganized = true, + SpawnOutdoorsman = true, + SpawnFastReader = true, + SpawnFastLearner = true, + SpawnHandy = true, + SpawnAxeMan = true, + SpawnBurglar = true, + SpawnGraceful = true, + SpawnDextrous = true, + SpawnInconspicuous = true, + SpawnKeenHearing = true, + }, + AegisEvents = { + -- Min: 1 Max: 10 Default: 3 + SiegeWaves = 3, + -- Min: 5 Max: 200 Default: 40 + SiegeCount = 40, + -- Min: 20 Max: 150 Default: 60 + SiegeDistance = 60, + -- Min: 0 Max: 50 Default: 12 + SiegeGap = 12, + -- Min: 4 Max: 30 Default: 10 + SiegeRadius = 10, + -- Min: 1 Max: 30 Default: 5 + SiegeLureMinutes = 5, + SiegeSprinters = false, + SiegeCrawlers = false, + SiegeGunshot = true, + -- Min: 1 Max: 96 Default: 8 + StormHours = 8, + -- Min: 0 Max: 20 Default: 6 + StormThunder = 6, + -- Min: 0.50 Max: 10.00 Default: 1.20 + StormThunderGap = 1.2, + -- Min: 0 Max: 200 Default: 15 + HeliCount = 15, + -- Min: 20 Max: 150 Default: 80 + HeliDistance = 80, + -- Min: 4 Max: 30 Default: 8 + HeliRadius = 8, + -- Min: 1 Max: 100 Default: 20 + AirdropCount = 20, + -- Min: 2 Max: 30 Default: 10 + AirdropRadius = 10, + -- Min: 1 Max: 8 Default: 5 + AirdropHeight = 5, + -- Min: 1 Max: 48 Default: 6 + FirestormHours = 6, + -- Min: 0 Max: 20 Default: 4 + FirestormThunder = 4, + -- Min: 1 Max: 6 Default: 3 + FirestormWaves = 3, + -- Min: 1 Max: 100 Default: 15 + FirestormCount = 15, + -- Min: 20 Max: 150 Default: 50 + FirestormDistance = 50, + AmbushRain = true, + -- Min: 1 Max: 100 Default: 25 + AmbushCount = 25, + -- Min: 2 Max: 20 Default: 6 + AmbushRadius = 6, + PlayerPanel = true, + }, + CaffeineMakesSense = { + EnableSleepPenaltyModel = true, + }, + DrinkSmart = { + AllowWaterDrinkLowThirst = false, + ShowSmartDrinkAmount = false, + AddSipOption = false, + }, + DGMC_Bolt_Cutters = { + Allow_Garage_Doors = true, + Allow_Fence_Gates = true, + Allow_Fences = true, + -- Min: 0 Max: 100 Default: 0 + Fence_Wire_Chance = 0, + Allow_Shutters = false, + -- Min: 0 Max: 10 Default: 3 + Easy_Strength_Req = 3, + -- Min: 0 Max: 10 Default: 5 + Medium_Strength_Req = 5, + -- Min: 0 Max: 10 Default: 7 + Hard_Strength_Req = 7, + -- Min: 0 Max: 60 Default: 22 + Base_Duration = 22, + -- Min: 0.00 Max: 40.00 Default: 4.00 + Base_Muscle_Strain = 4.0, + Debug_Logging = false, + }, + FWOFitness = { + InitialPerkBonus = true, + currentExerciseRegularityBonus = true, + -- Min: 0 Max: 100 Default: 25 + currentExerciseOffset = 25, + -- Min: 0.01 Max: 100.00 Default: 5.00 + currentExerciseRate = 5.0, + -- Min: 0.00 Max: 100.00 Default: 6.00 + AverageExerciseRegularityBonus = 6.0, + -- Min: 0.00 Max: 100.00 Default: 0.30 + LevelBonus = 0.3, + SpaceOutExercise = true, + -- Min: 0.00 Max: 100.00 Default: 0.90 + SpaceOutExerciseNegative = 0.9, + RestedBonus = true, + -- Min: 0.00 Max: 10.00 Default: 0.90 + RestedBonusNegative = 0.9, + -- Min: 0.01 Max: 10.00 Default: 1.00 + XPMultiplier = 1.0, + -- Min: 0.00 Max: 10.00 Default: 1.00 + PassiveMultiplier = 1.0, + -- Min: 0.00 Max: 10.00 Default: 1.00 + BoredomMultiplier = 1.0, + -- Min: 0.00 Max: 10.00 Default: 1.00 + UnhappynessMultiplier = 1.0, + DropBags = false, + KeepBagsOn = false, + }, + FWOWorkingTreadmill = { + -- Min: 0.00 Max: 100.00 Default: 1.00 + StrengthXPMultiply = 1.0, + -- Min: 0.00 Max: 100.00 Default: 1.00 + SprintingXPMultiply = 1.0, + -- Min: 0.00 Max: 5.00 Default: 1.00 + HeatMultiplier = 1.0, + -- Min: 0.00 Max: 5.00 Default: 1.00 + ThirstMultiplier = 1.0, + TreadmillDropBags = false, + BenchpressDropBags = false, + BenchTreadKeepBagsOn = false, + }, + LighterConfig = { + -- Min: 1 Max: 500 Default: 100 + MaxLighterUses = 100, + -- Min: 1 Max: 100 Default: 20 + MaxMatchesUses = 20, + -- Min: 1 Max: 500 Default: 100 + MaxDisposableLighterUses = 100, + }, + STA_PryOpen = { + PryEnablePity = false, + -- Min: 0.01 Max: 1.00 Default: 0.25 + PryChanceBase = 0.25, + -- Min: 0.00 Max: 1.00 Default: 0.03 + PryBonusSkillStrength = 0.03, + -- Min: 0.00 Max: 1.00 Default: 0.03 + PryBonusSkillCarpentry = 0.03, + -- Min: 0.00 Max: 1.00 Default: 0.03 + PryBonusSkillBlacksmith = 0.03, + -- Min: 0.00 Max: 1.00 Default: 0.03 + PryBonusSkillMechanics = 0.03, + -- Min: 0.00 Max: 1.00 Default: 0.15 + PryBonusTraitBurglar = 0.15, + -- Min: 0.00 Max: 5.00 Default: 0.20 + PryBonusSkillNimble = 0.2, + -- Min: 0.00 Max: 5.00 Default: 1.00 + PryBonusTraitDextrous = 1.0, + PryEnableBuilding = true, + -- Min: 0 Max: 10 Default: 3 + PryLevelBuilding = 3, + -- Min: 0.01 Max: 5.00 Default: 1.00 + PryChanceMultiplierBuilding = 1.0, + -- Min: 1 Max: 30 Default: 8 + PryTimeBuilding = 8, + PryEnableWindow = true, + -- Min: 0 Max: 10 Default: 2 + PryLevelWindow = 2, + -- Min: 0.01 Max: 5.00 Default: 1.10 + PryChanceMultiplierWindow = 1.1, + -- Min: 1 Max: 30 Default: 6 + PryTimeWindow = 6, + PryEnableGarage = true, + -- Min: 0 Max: 10 Default: 6 + PryLevelGarage = 6, + -- Min: 0.01 Max: 5.00 Default: 0.85 + PryChanceMultiplierGarage = 0.85, + -- Min: 1 Max: 30 Default: 10 + PryTimeGarage = 10, + PryEnableSecure = true, + -- Min: 0 Max: 10 Default: 8 + PryLevelSecure = 8, + -- Min: 0.01 Max: 5.00 Default: 0.80 + PryChanceMultiplierSecure = 0.8, + -- Min: 1 Max: 30 Default: 14 + PryTimeSecure = 14, + PryEnableVehicle = true, + -- Min: 0 Max: 10 Default: 3 + PryLevelVehicle = 3, + -- Min: 0.01 Max: 5.00 Default: 1.00 + PryChanceMultiplierVehicle = 1.0, + -- Min: 1 Max: 30 Default: 10 + PryTimeVehicle = 10, + PryEnableTrunk = true, + -- Min: 0 Max: 10 Default: 2 + PryLevelTrunk = 2, + -- Min: 0.01 Max: 5.00 Default: 1.05 + PryChanceMultiplierTrunk = 1.05, + -- Min: 1 Max: 30 Default: 8 + PryTimeTrunk = 8, + -- Min: 0.00 Max: 1.00 Default: 0.30 + PryChanceBreakWindow = 0.3, + -- Min: 0.00 Max: 1.00 Default: 0.20 + PryChanceBreakVehicleWindow = 0.2, + -- Min: 0.00 Max: 1.00 Default: 0.15 + PryChanceBreakVehicleLock = 0.15, + -- Min: 0.00 Max: 1.00 Default: 0.08 + PryChanceInjury = 0.08, + -- Min: 0.00 Max: 1.00 Default: 0.05 + PryBonusTraitSkin = 0.05, + -- Min: 0.00 Max: 1.00 Default: 0.65 + PryChanceInjurySeverity01 = 0.65, + -- Min: 0.00 Max: 1.00 Default: 0.30 + PryChanceInjurySeverity02 = 0.3, + -- Min: 0.00 Max: 1.00 Default: 0.05 + PryChanceInjurySeverity03 = 0.05, + -- Min: 5 Max: 100 Default: 15 + PryNoiseRadius = 15, + -- Min: 0.00 Max: 10.00 Default: 0.50 + PryBonusSkillSneak = 0.5, + PryEnableAlarmSuccess = true, + PryEnableAlarmForce = true, + -- Min: 0.00 Max: 1.00 Default: 0.12 + PryChanceAlarm = 0.12, + -- Min: 0.00 Max: 1.00 Default: 0.01 + PryBonusSkillElectricity = 0.01, + PryToolItemsList = "", + PryToolTagsList = "base:crowbar:1.0;", + }, + ImmersiveSuicide = { + ForceZombification = false, + ShowConfirmationModal = true, + }, + WashSmart = { + AllowTaintedWater = true, + -- Min: 0.50 Max: 10.00 Default: 4.00 + BandageWaterPerItem = 4.0, + }, + ComputerMod = { + -- Min: 0 Max: 100 Default: 14 + DiscSpawnChance = 14, + -- Min: 0 Max: 300 Default: 100 + GameDiscWeightPercent = 100, + -- Min: 0 Max: 300 Default: 100 + SystemDiscWeightPercent = 100, + -- Min: 0 Max: 300 Default: 100 + BlankDiscWeightPercent = 100, + -- Min: 0 Max: 300 Default: 100 + HackDiscWeightPercent = 100, + -- Min: 0 Max: 100 Default: 60 + PreinstalledGameChance = 60, + -- Min: 0 Max: 100 Default: 34 + PasswordChance = 34, + -- Min: 0 Max: 100 Default: 12 + FramePasswordNoteChance = 12, + -- Min: 0 Max: 100 Default: 18 + NearbyPasswordNoteChance = 18, + -- Min: 0 Max: 10 Default: 1 + HackRequiredElectricalLevel = 1, + -- Min: 0 Max: 100 Default: 28 + EmptyFolderChance = 28, + -- Min: 0 Max: 100 Default: 12 + FolderMagazineChance = 12, + -- Min: 0 Max: 100 Default: 18 + FolderNewspaperChance = 18, + -- Min: 0 Max: 100 Default: 9 + FolderVideoChance = 9, + -- Min: 0 Max: 100 Default: 10 + PaintFileChance = 10, + EnableGameInstallVirus = true, + -- Min: 0 Max: 100 Default: 8 + GameInstallVirusChance = 8, + EnableBoardApp = true, + EnableChatApp = true, + EnableCommerceApp = true, + NetworkOutageOnPowerLoss = true, + NetworkTerminalNeedsPower = true, + -- Min: 1 Max: 168 Default: 24 + MarketShopRefreshHours = 24, + -- Min: 1 Max: 168 Default: 24 + MarketJobRefreshHours = 24, + -- Min: 0 Max: 100 Default: 42 + MailAccountChance = 42, + -- Min: 0 Max: 100 Default: 55 + MailLoggedInChance = 55, + -- Min: 0 Max: 100 Default: 28 + SecretSiteHintChance = 28, + }, + ButtstrokeOption = { + -- Min: 0.00 Max: 200.00 Default: 5.00 + Damage = 5.0, + -- Min: 0.00 Max: 100.00 Default: 0.01 + EnduranceLost = 0.005, + -- Min: 0 Max: 100 Default: 1 + WeaponConditionLost = 1, + }, + FunctionalAppliances = { + BeerKegsChance = 2, + BeerKegsFilledAmount = 3, + SyrupsChance = 2, + SyrupsFilledAmount = 3, + FATheatreChance = 3, + FAFreshTheatreChance = 3, + FAZombieItemsSpawn = false, + }, + PIP = { + EnableAutoWatering = true, + -- Min: 1 Max: 60 Default: 10 + WateringInterval = 10, + -- Min: 0 Max: 10 Default: 0 + WateringRadius = 0, + SmartPipes = true, + -- Min: 3 Max: 100 Default: 20 + SmartPipesFillMax = 20, + SharedWaterPool = true, + EnableFertigation = true, + -- Min: 0 Max: 10 Default: 5 + FertigationSkill = 5, + -- Min: 1 Max: 100 Default: 10 + ChargesPerBag = 10, + DebugLogs = false, + }, + PlayablePool = { + -- Min: 0 Max: 100 Default: 18 + BoredomReliefPerTurn = 18, + -- Min: 3 Max: 30 Default: 8 + MaxPlayDistance = 8, + AllowAdminSoloPractice = true, + AllowSpectators = true, + EnableBetaMinigames = false, + -- Min: 1 Max: 120 Default: 20 + AbandonedSessionMinutes = 20, + -- Min: 0 Max: 100 Default: 0 + StressReliefPerTurn = 0, + -- Min: 0 Max: 100 Default: 0 + UnhappinessReliefPerTurn = 0, + }, + PSR = { + ChargeFreq = 1, + -- Min: 1 Max: 100 Default: 25 + solarPanelEfficiency = 25, + -- Min: 0 Max: 1000 Default: 100 + batteryDegradeChance = 100, + -- Min: 1 Max: 1000 Default: 100 + consumptionMultiplier = 100, + -- Min: 1 Max: 10000 Default: 100 + DIYBatteryMultiplier = 100, + -- Min: 0 Max: 100 Default: 25 + solarPanelWorldSpawns = 20, + BatteryBankSpawn = 3, + -- Min: 0.00 Max: 100.00 Default: 1.00 + LRMSolarPanels = 1.0, + -- Min: 0.00 Max: 100.00 Default: 1.00 + LRMBatteries = 1.0, + -- Min: 0.00 Max: 100.00 Default: 1.00 + LRMMisc = 1.0, + -- Min: 1 Max: 1440 Default: 30 + ConnectPanelMin = 20, + -- Min: 0 Max: 50 Default: 0 + BackupConnectRange = 0, + HardenedPanelRecipe = true, + }, + Snowman = { + Melt = true, + }, + NewMusic = { + -- Min: 0 Max: 36000 Default: 1500 + MaxTrackingRange = 1500, + -- Min: 4 Max: 50 Default: 10 + ActiveDeviceLimit = 10, + -- Min: 0.02 Max: 1000.00 Default: 24.00 + BatteryDrainRate = 24.0, + -- Min: 9 Max: 100 Default: 35 + AudioMaxRadius = 35, + FancyUI = true, + Disassembly = true, + ZomboidOST = false, + -- Min: 0.00 Max: 4.00 Default: 0.60 + CassettesSpawnRate = 0.5, + -- Min: 0.00 Max: 4.00 Default: 0.60 + VinylRecordsSpawnRate = 0.4, + -- Min: 0.00 Max: 4.00 Default: 0.60 + CDsSpawnRate = 0.4, + -- Min: 0.00 Max: 4.00 Default: 0.60 + WalkmanSpawnRate = 0.5, + -- Min: 0.00 Max: 4.00 Default: 0.60 + BoomboxSpawnRate = 0.6, + -- Min: 0.00 Max: 4.00 Default: 0.60 + CDPlayerSpawnRate = 0.5, + -- Min: 0.00 Max: 4.00 Default: 0.60 + RecordPlayerSpawnRate = 0.5, + -- Min: 0.00 Max: 4.00 Default: 0.60 + MusicalZombiesSpawnRate = 0.4, + }, + B42Horticulture = { + LearnedRecipe = true, + }, + SapphCooking = { + NonPerishableChance = 3, + PerishableChance = 3, + SpicesSpawnChance = 3, + CannedSpawnChance = 3, + MagazineChance = 3, + MREChance = 2, + KitchenUtensilsChance = 3, + AlcoholChance = 3, + ZombieLootSpawn = 3, + }, + DGMC_Cleaning_Wipes = { + Clean_Body = true, + Clean_Clothing = true, + Clean_Weapons = true, + Remove_Makeup = true, + -- Min: 0.00 Max: 10.00 Default: 1.00 + Speed_Mult = 1.0, + -- Min: 0 Max: 100 Default: 25 + Wetness = 25, + Debug_Logging = false, + }, + ammomakerOptions = { + -- Min: 1 Max: 10 Default: 1 + CraftingSpeed = 1, + -- Min: 1 Max: 100 Default: 10 + NitreYield = 10, + -- Min: 1 Max: 5 Default: 1 + BirdExYield = 1, + -- Min: 1 Max: 200 Default: 8 + BirdExSpawnMin = 8, + -- Min: 1 Max: 200 Default: 24 + BirdExSpawnMax = 24, + -- Min: 1 Max: 10 Default: 1 + BirdFeatherSpawnMin = 1, + -- Min: 1 Max: 10 Default: 3 + BirdFeatherSpawnMax = 3, + -- Min: 1 Max: 20 Default: 1 + CasingsSpawnMin = 1, + -- Min: 1 Max: 20 Default: 3 + CasingsSpawnMax = 3, + -- Min: 1 Max: 720 Default: 168 + DroppedCasingsLifetime = 168, + -- Min: 10 Max: 100 Default: 10 + ProduceAmmoBulkSize = 10, + AllowConvertRecipes = false, + -- Min: 0.00 Max: 30.00 Default: 10.00 + ChanceArmyStorageAmmunition = 10.0, + -- Min: 0.00 Max: 30.00 Default: 10.00 + ChanceArmySurplusMisc = 10.0, + -- Min: 0.00 Max: 20.00 Default: 5.00 + ChanceDrugLabGuns = 5.0, + -- Min: 0.00 Max: 20.00 Default: 4.00 + ChanceFirearmWeapons = 4.0, + -- Min: 0.00 Max: 20.00 Default: 4.00 + ChanceFirearmWeapons_Mid = 4.0, + -- Min: 0.00 Max: 20.00 Default: 4.00 + ChanceFirearmWeapons_Late = 4.0, + -- Min: 0.00 Max: 20.00 Default: 10.00 + ChanceGunStoreAmmunition = 10.0, + -- Min: 0.00 Max: 50.00 Default: 15.00 + ChanceGunStoreMagsAmmo = 15.0, + -- Min: 0.00 Max: 20.00 Default: 5.00 + ChanceGunStoreGuns = 5.0, + -- Min: 0.00 Max: 20.00 Default: 3.00 + ChancePoliceStorageAmmunition = 3.0, + -- Min: 0.00 Max: 20.00 Default: 3.00 + ChancePoliceStorageGuns = 3.0, + -- Min: 0.00 Max: 2.00 Default: 0.10 + ChanceWardrobeRedneck = 0.1, + -- Min: 0.00 Max: 50.00 Default: 15.00 + ChanceGunStorePistols = 15.0, + -- Min: 0.00 Max: 50.00 Default: 10.00 + ChanceGunStoreRifles = 10.0, + -- Min: 0.00 Max: 50.00 Default: 10.00 + ChanceGunStoreShotguns = 10.0, + -- Min: 0.00 Max: 10.00 Default: 5.00 + ChanceHuntingLockers = 5.0, + -- Min: 0.00 Max: 5.00 Default: 1.00 + ChanceArmyBunkerStorage = 1.0, + -- Min: 0.00 Max: 2.00 Default: 0.40 + ChanceLockerArmyBedroomHome = 0.4, + -- Min: 0.00 Max: 50.00 Default: 35.00 + ChancePoliceEvidence = 35.0, + -- Min: 0.00 Max: 5.00 Default: 0.50 + ChanceBedroomDresserRedneck = 0.5, + -- Min: 0.00 Max: 10.00 Default: 4.00 + ChanceDrugShackWeapons = 4.0, + -- Min: 0.00 Max: 8.00 Default: 4.00 + ChanceGarageFirearms = 4.0, + -- Min: 0.00 Max: 2.00 Default: 0.03 + ChanceBedroomSidetable = 0.03, + -- Min: 0.00 Max: 2.00 Default: 0.02 + ChanceBedroomSidetableClassy = 0.02, + -- Min: 0.00 Max: 2.00 Default: 0.06 + ChanceBedroomSidetableRedneck = 0.06, + -- Min: 0.00 Max: 2.00 Default: 0.04 + ChanceDresserGeneric = 0.04, + -- Min: 0.00 Max: 10.00 Default: 5.00 + ChancePlankStashGun = 5.0, + -- Min: 0.00 Max: 10.00 Default: 2.00 + ChanceSecurityDesk = 2.0, + -- Min: 0.00 Max: 10.00 Default: 2.00 + ChanceSecurityLockers = 2.0, + -- Min: 0.00 Max: 10.00 Default: 4.00 + ChanceHunter = 4.0, + -- Min: 0.00 Max: 20.00 Default: 5.00 + ChancePrisonArmoryShotguns = 5.0, + }, + B42Survival = { + LearnedRecipe = true, + TorchSmoking = true, + }, + GWG = { + -- Min: 0 Max: 5 Default: 0 + MultiplayerTick = 0, + }, + MarzGuns = { + Enable_9x19 = true, + Enable_38 = true, + Enable_45 = true, + Enable_357 = true, + Enable_44 = true, + Enable_308 = true, + Enable_762x51 = true, + Enable_223 = true, + Enable_556x45 = true, + Enable_556x45_HollowPoint = true, + Enable_556x45_ArmorPiercing = true, + Enable_556x45_Subsonic = true, + Enable_556x45_Overpressured = true, + Enable_3030 = true, + Enable_12Gauge_Buckshot = true, + Enable_12Gauge_Slug = true, + Enable_40mm_Buckshot = true, + Enable_40mm_HE = true, + Enable_40mm_Incendiary = true, + Enable_50 = true, + Enable_4570 = true, + Enable_762x39 = true, + Enable_9x39 = true, + Enable_545x39 = true, + Enable_762x54 = true, + Enable_3006 = true, + Enable_M16A1 = true, + Enable_M16A2 = true, + Enable_M16A2_M203 = true, + Enable_M16A3 = true, + Enable_AR15 = true, + Enable_FNC = true, + Enable_M4 = true, + Enable_G36 = true, + Enable_G36C = true, + Enable_AK74 = true, + Enable_AKS74U = true, + Enable_ASVAL = true, + Enable_FAMAS = true, + Enable_CAR15 = true, + Enable_XM177 = true, + Enable_M4A1 = true, + Enable_AK47 = true, + Enable_M14 = true, + Enable_M1_GARAND = true, + Enable_FAL = true, + Enable_G3 = true, + Enable_MOSIN = true, + Enable_M24 = true, + Enable_M1903 = true, + Enable_M79 = true, + Enable_W1894 = true, + Enable_M1895 = true, + Enable_W1887 = true, + Enable_W1873 = true, + Enable_W1873_CARBINE = true, + Enable_M60 = true, + Enable_BAR = true, + Enable_M92FS = true, + Enable_M93R = true, + Enable_P226 = true, + Enable_HIPOWER = true, + Enable_M1911 = true, + Enable_USP = true, + Enable_DEAGLE = true, + Enable_SW629 = true, + Enable_PYTHON = true, + Enable_RHINO = true, + Enable_MP412 = true, + Enable_COLT_SINGLE = true, + Enable_DETECTIVE_38 = true, + Enable_SVD = true, + Enable_SKS = true, + Enable_PSG1 = true, + Enable_MOSSBERG_590 = true, + Enable_TRENCHGUN = true, + Enable_BENELLI_M4 = true, + Enable_SPAS12 = true, + Enable_STEVENS_555 = true, + Enable_DOUBLEBARREL = true, + Enable_AA12 = true, + Enable_REMINGTON_870 = true, + Enable_THOMPSON = true, + Enable_MP5 = true, + Enable_MP5A2 = true, + Enable_MP5SD = true, + Enable_MP5K = true, + Enable_TEC9 = true, + Enable_MAC10 = true, + Enable_Explosives = true, + Enable_VanillaWeaponReplacement = true, + Enable_VanillaAmmoReplacement = true, + Enable_TacticalReload = false, + }, + LG = { + SpawnChance = 4, + }, + JordanalSpawns = { + -- Min: 0.00 Max: 100.00 Default: 0.04 + FireFighter_UnitChance_FireDept = 0.04, + -- Min: 0.00 Max: 100.00 Default: 0.04 + SWAT_UnitChance = 0.04, + -- Min: 0.00 Max: 100.00 Default: 0.02 + SWAT_UnitChance_General = 0.02, + -- Min: 0.00 Max: 100.00 Default: 0.02 + Trauma_ResponderChance = 0.02, + -- Min: 0.00 Max: 100.00 Default: 0.01 + Trauma_ResponderChance_General = 0.01, + -- Min: 0.00 Max: 100.00 Default: 0.04 + Trauma_ResponderChance_Medical = 0.04, + -- Min: 0.00 Max: 100.00 Default: 0.04 + Desert_Camo_UnitChance = 0.04, + -- Min: 0.00 Max: 100.00 Default: 0.02 + Desert_Camo_UnitChance_General = 0.02, + }, + ProjectArcade = { + DisableDefaultPrizePool = false, + ReplaceVanillaArcadesOnLoad = false, + ReplaceVanillaPinballsOnLoad = false, + -- Min: 0 Max: 100 Default: 100 + SfxVolumePct = 75, + DisableArcadeAmbientSound = false, + AnnouncementLanguage = 1, + CurrencyFullType = "Base.SilverCoin", + -- Min: 0 Max: 300 Default: 100 + CoinDistContainersPct = 100, + -- Min: 0 Max: 300 Default: 100 + CoinDistZombiesPct = 50, + -- Min: 0 Max: 300 Default: 100 + ROMDistPct = 70, + }, + MoreImmersiveVehicles = { + -- Min: 0 Max: 100 Default: 5 + ParkOpenedDoorChance = 5, + -- Min: 0 Max: 100 Default: 10 + ParkOpenedTrunkDoorChance = 7, + -- Min: 0 Max: 100 Default: 3 + ParkOpenedEngineDoorChance = 3, + -- Min: 0 Max: 100 Default: 5 + ParkOpenedWindowChance = 5, + -- Min: 0 Max: 100 Default: 35 + RoadOpenedDoorChance = 35, + -- Min: 0 Max: 100 Default: 45 + RoadOpenedTrunkDoorChance = 25, + -- Min: 0 Max: 100 Default: 12 + RoadOpenedEngineDoorChance = 5, + -- Min: 0 Max: 100 Default: 20 + RoadOpenedWindowChance = 15, + }, + GamestaVehicleZones = { + -- Min: -1 Max: 100 Default: -1 + spawnRate = -1, + -- Min: -1 Max: 100 Default: -1 + spawnRateModifiedTrafficJams = -1, + trafficjamsLV = true, + trafficjamsExtra = true, + vehicleCorpseDistribution = 2, + climbVehicles = false, + noGoodCars = true, + interactBombVehicle = false, + autoVehicleFuelPumps = true, + randomAngle = true, + weatherEffects = true, + earlyExitVehicle = true, + -- Min: 0.00 Max: 3.00 Default: 1.00 + earlyExitVehicleDamage = 1.0, + -- Min: -1 Max: 100 Default: -1 + spawnRateBurnt = -1, + -- Min: -0.10 Max: 1.30 Default: -0.10 + baseVehicleQuality = -0.1, + -- Min: -1 Max: 100 Default: -1 + chanceToPartDamage = -1, + }, + VMZ = { + RoadStories = true, + -- Min: 0.00 Max: 2.00 Default: 1.00 + RoadStoriesMultiplier = 0.4, + SpecCar = false, + -- Min: 0 Max: 100 Default: 16 + SpawnRate = 12, + -- Min: 0 Max: 100 Default: 50 + VehiCond = 33, + -- Min: 0 Max: 100 Default: 0 + PartDamage = 25, + -- Min: 0 Max: 100 Default: 70 + KeySpawn = 40, + }, + VVR = { + NoTrailers = false, + NoBurnt = false, + -- Min: 0 Max: 100 Default: 10 + VehiCond = 10, + VehiclesBlacklist = "Base.ModernCar_Martin;", + }, + ImmersiveHotwire = { + Screwdrivers = "Base.Screwdriver;Base.Screwdriver_Old;Base.Screwdriver_Improvised;Base.Multitool;Base.Handiknife", + ScrewdriversTags = "", + Pliers = "Base.Pliers;Base.Multitool", + PliersTags = "", + HotwireEveryTime = false, + DucttapeNeededToUnhotwire = true, + ShowDragLine = true, + }, +} diff --git a/ansible/roles/podman/files/zomboid/sophie/spawnpoints.lua b/ansible/roles/podman/files/zomboid/sophie/spawnpoints.lua new file mode 100644 index 0000000..4116d44 --- /dev/null +++ b/ansible/roles/podman/files/zomboid/sophie/spawnpoints.lua @@ -0,0 +1,7 @@ +function SpawnPoints() + return { + unemployed = { + { worldX = 40, worldY = 22, posX = 67, posY = 201 } + } + } +end diff --git a/ansible/roles/podman/files/zomboid/sophie/spawnregions.lua b/ansible/roles/podman/files/zomboid/sophie/spawnregions.lua new file mode 100644 index 0000000..106cb04 --- /dev/null +++ b/ansible/roles/podman/files/zomboid/sophie/spawnregions.lua @@ -0,0 +1,15 @@ +function SpawnRegions() + return { + { name = "Brandenburg, KY", file = "media/maps/Brandenburg, KY/spawnpoints.lua" }, + { name = "Echo Creek, KY", file = "media/maps/Echo Creek, KY/spawnpoints.lua" }, + { name = "Ekron, KY", file = "media/maps/Ekron, KY/spawnpoints.lua" }, + { name = "Fallas Lake, KY", file = "media/maps/Fallas Lake, KY/spawnpoints.lua" }, + { name = "Irvington, KY", file = "media/maps/Irvington, KY/spawnpoints.lua" }, + { name = "March Ridge, KY", file = "media/maps/March Ridge, KY/spawnpoints.lua" }, + { name = "Muldraugh, KY", file = "media/maps/Muldraugh, KY/spawnpoints.lua" }, + { name = "Riverside, KY", file = "media/maps/Riverside, KY/spawnpoints.lua" }, + { name = "Rosewood, KY", file = "media/maps/Rosewood, KY/spawnpoints.lua" }, + { name = "Valley Station, KY", file = "media/maps/Valley Station, KY/spawnpoints.lua" }, + { name = "West Point, KY", file = "media/maps/West Point, KY/spawnpoints.lua" }, + } +end diff --git a/ansible/roles/podman/tasks/containers/home/zomboid.yml b/ansible/roles/podman/tasks/containers/home/zomboid.yml index 3462fa2..6f4dc79 100644 --- a/ansible/roles/podman/tasks/containers/home/zomboid.yml +++ b/ansible/roles/podman/tasks/containers/home/zomboid.yml @@ -1,4 +1,9 @@ --- +- name: load vendored sophie modlist + ansible.builtin.include_vars: + file: zomboid_sophie_mods.yml + tags: zomboid-conf + - name: create zomboid host directory volumes become: true ansible.builtin.file: @@ -122,6 +127,65 @@ mode: 0644 notify: restorecon podman +# Server config is seeded from the vendored Sophie 42 preset *before* first +# boot, so the server never generates a vanilla INI we then have to patch. +# +# force is off by design: these files are a starting point, not a managed +# state. Stop the server, hand-edit them, regenerate the world -- Ansible will +# not clobber the edits on the next deploy. Re-push deliberately with +# -e zomboid_config_force=true. +- name: create zomboid server config directory + become: true + ansible.builtin.file: + path: "{{ zomboid_path }}/data/Server" + state: directory + owner: "{{ podman_subuid.stdout }}" + group: "{{ podman_user }}" + mode: 0755 + notify: restorecon podman + tags: zomboid-conf + +- name: seed zomboid server ini from sophie preset + become: true + ansible.builtin.template: + src: zomboid/server.ini.j2 + dest: "{{ zomboid_path }}/data/Server/{{ zomboid_server_name }}.ini" + force: "{{ zomboid_config_force | bool }}" + owner: "{{ podman_subuid.stdout }}" + group: "{{ podman_user }}" + mode: 0644 + notify: restorecon podman + tags: zomboid-conf + +# Copied, not templated: these are Lua and must not go through Jinja. +- name: seed zomboid sandbox and spawn config from sophie preset + become: true + ansible.builtin.copy: + src: "zomboid/sophie/{{ item }}.lua" + dest: "{{ zomboid_path }}/data/Server/{{ zomboid_server_name }}_{{ item }}.lua" + force: "{{ zomboid_config_force | bool }}" + owner: "{{ podman_subuid.stdout }}" + group: "{{ podman_user }}" + mode: 0644 + loop: + - SandboxVars + - spawnregions + - spawnpoints + notify: restorecon podman + tags: zomboid-conf + +# The server's own logs, not the container's. PZ holds these fds open for the +# life of the process, so copytruncate is mandatory -- a rename would leave it +# writing into an unlinked inode and the file would appear to stop growing. +- name: deploy zomboid logrotate config + become: true + ansible.builtin.template: + src: zomboid/logrotate.j2 + dest: /etc/logrotate.d/zomboid + owner: root + group: root + mode: 0644 + # Set volume permissions for steam user (UID 1000) inside container # This uses podman unshare to set ownership correctly for rootless podman - name: set zomboid volume permissions for steam user @@ -147,11 +211,13 @@ name: zomboid image: "{{ image }}" restart_policy: on-failure:3 - log_driver: journald + log_driver: k8s-file + log_opt: + max_size: 50m env: - SERVER_NAME: "{{ zomboid_server_names[zomboid_server_mode] }}" - MIN_RAM: 8g - MAX_RAM: 24g + SERVER_NAME: "{{ zomboid_server_name }}" + MIN_RAM: "{{ zomboid_min_ram }}" + MAX_RAM: "{{ zomboid_max_ram }}" AUTO_UPDATE: "true" ADMIN_PASSWORD: "{{ zomboid_admin_password }}" SERVER_PASSWORD: "{{ zomboid_password }}" @@ -183,102 +249,6 @@ line: "Restart=always" notify: reload zomboid systemd -# Check if server INI exists (generated on first server run) -- name: check if zomboid server ini exists - become: true - ansible.builtin.stat: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - register: zomboid_ini_stat - tags: zomboid-conf - -# Backup settings (requires server to have run once to generate ini) -- name: configure zomboid backup settings - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - loop: - - { key: "SaveWorldEveryMinutes", value: "10" } - - { key: "BackupsPeriod", value: "30" } - - { key: "BackupsCount", value: "10" } - # B42 Linux server fix: disable Lua checksum to allow mods to load - - { key: "DoLuaChecksum", value: "false" } - # Server password - - { key: "Password", value: "{{ zomboid_password }}" } - when: zomboid_ini_stat.stat.exists - tags: zomboid-conf - -# Discord integration (uses Gregbot token, posts /all chat to Discord) -- name: configure zomboid discord integration - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - loop: - - { key: "DiscordEnable", value: "true" } - - { key: "DiscordToken", value: "{{ zomboid_discord_token }}" } - - { key: "DiscordChannel", value: "zomboidbot" } - - { key: "DiscordChannelID", value: "1451961291194241095" } - when: zomboid_ini_stat.stat.exists - tags: zomboid-conf - -# RCON configuration for remote administration -- name: configure zomboid rcon - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - loop: - - { key: "RCONPort", value: "{{ zomboid_rcon_port }}" } - - { key: "RCONPassword", value: "{{ zomboid_admin_password }}" } - when: zomboid_ini_stat.stat.exists - tags: zomboid-conf - -# Mod configuration for 'modded' server profile -- name: configure zomboid mods for modded server - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - loop: - - { key: "Mods", value: "{{ zomboid_mods.mod_ids }}" } - - { key: "WorkshopItems", value: "{{ zomboid_mods.workshop_items }}" } - when: - - zomboid_server_mode == 'modded' - - zomboid_ini_stat.stat.exists - tags: zomboid-conf - -# Mod configuration for 'b42revamp' server profile (168 mods from Steam collection) -- name: configure zomboid mods for b42revamp server - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^{{ item.key }}=" - line: "{{ item.key }}={{ item.value }}" - loop: - - { key: "Mods", value: "{{ zomboid_mods_b42revamp.mod_ids }}" } - - { key: "WorkshopItems", value: "{{ zomboid_mods_b42revamp.workshop_items }}" } - when: - - zomboid_server_mode == 'b42revamp' - - zomboid_ini_stat.stat.exists - tags: zomboid-conf - -# Map configuration (for modded servers with custom maps) -- name: configure zomboid map - become: true - ansible.builtin.lineinfile: - path: "{{ zomboid_path }}/data/Server/{{ zomboid_server_names[zomboid_server_mode] }}.ini" - regexp: "^Map=" - line: "Map={{ zomboid_maps[zomboid_server_mode] }}" - when: - - zomboid_server_mode != 'vanilla' - - zomboid_ini_stat.stat.exists - tags: zomboid-conf - # Firewall logging for player IP correlation # Logs new UDP connections to Zomboid port for IP address tracking - name: add firewall rule to log zomboid connections diff --git a/ansible/roles/podman/tasks/main.yml b/ansible/roles/podman/tasks/main.yml index 6e49b0f..9d80831 100644 --- a/ansible/roles/podman/tasks/main.yml +++ b/ansible/roles/podman/tasks/main.yml @@ -126,7 +126,8 @@ image: localhost/greg-time-bot:3.14.1 tags: gregtime -# Gated off by default — see zomboid_enabled in roles/podman/defaults/main.yml. +# Gated on zomboid_enabled (roles/podman/defaults/main.yml) so it can be taken +# down for a CI-heavy stretch without losing the world. - import_tasks: containers/home/zomboid.yml vars: image: docker.io/cm2network/steamcmd:root diff --git a/ansible/roles/podman/templates/zomboid/entrypoint.sh.j2 b/ansible/roles/podman/templates/zomboid/entrypoint.sh.j2 index cfc4054..049e743 100644 --- a/ansible/roles/podman/templates/zomboid/entrypoint.sh.j2 +++ b/ansible/roles/podman/templates/zomboid/entrypoint.sh.j2 @@ -10,10 +10,10 @@ STEAMCMD="/home/steam/steamcmd/steamcmd.sh" SERVER_NAME="${SERVER_NAME:-zomboid}" PUID="${PUID:-1000}" PGID="${PGID:-1000}" -MIN_RAM="${MIN_RAM:-4g}" -MAX_RAM="${MAX_RAM:-8g}" +MIN_RAM="${MIN_RAM:-{{ zomboid_min_ram }}}" +MAX_RAM="${MAX_RAM:-{{ zomboid_max_ram }}}" -echo "=== Project Zomboid Build 42 Server ===" +echo "=== Project Zomboid Build 42 Server ({{ zomboid_preset_version }}) ===" echo "Server Name: ${SERVER_NAME}" echo "RAM: ${MIN_RAM} - ${MAX_RAM}" @@ -21,7 +21,15 @@ echo "RAM: ${MIN_RAM} - ${MAX_RAM}" echo "=== Setting file permissions ===" usermod -o -u "${PUID}" steam groupmod -o -g "${PGID}" steam -chown -R steam:steam "${INSTALL_DIR}" "${CONFIG_DIR}" +for dir in "${INSTALL_DIR}" "${CONFIG_DIR}"; do + # Recursing is a full inode walk over the install tree -- with 256 workshop + # mods that is real SSD churn on every restart, and a no-op after the first. + if [ "$(stat -c %u "${dir}")" = "${PUID}" ]; then + echo "=== ${dir} already owned by ${PUID}, skipping recursive chown ===" + else + chown -R steam:steam "${dir}" + fi +done # Only chown writable parts of /home/steam (not read-only mounts) chown steam:steam /home/steam chown -R steam:steam /home/steam/steamcmd 2>/dev/null || true @@ -32,9 +40,9 @@ mkdir -p "${CONFIG_DIR}/Server" mkdir -p "${CONFIG_DIR}/Saves" mkdir -p "${CONFIG_DIR}/db" -# Update/Install PZ dedicated server with Build 42 unstable branch +# Update/Install PZ dedicated server from the default (stable) branch if [ "${AUTO_UPDATE:-true}" = "true" ]; then - echo "=== Updating Project Zomboid Server (Build 42 unstable) ===" + echo "=== Updating Project Zomboid Server (Build 42 stable) ===" su -c "${STEAMCMD} +runscript /home/steam/install.scmd" steam echo "=== Update complete ===" fi diff --git a/ansible/roles/podman/templates/zomboid/install.scmd.j2 b/ansible/roles/podman/templates/zomboid/install.scmd.j2 index 3855ebd..9acf740 100644 --- a/ansible/roles/podman/templates/zomboid/install.scmd.j2 +++ b/ansible/roles/podman/templates/zomboid/install.scmd.j2 @@ -12,7 +12,8 @@ force_install_dir /project-zomboid login anonymous -// Install/Update the Project Zomboid Dedicated Server - Unstable Branch (Build 42) -app_update 380870 -beta unstable validate +// Install/Update the Project Zomboid Dedicated Server (Build 42, stable) +// No -beta: B42 became the default branch at 42.20. +app_update 380870 validate quit diff --git a/ansible/roles/podman/templates/zomboid/logrotate.j2 b/ansible/roles/podman/templates/zomboid/logrotate.j2 new file mode 100644 index 0000000..0908b6c --- /dev/null +++ b/ansible/roles/podman/templates/zomboid/logrotate.j2 @@ -0,0 +1,23 @@ +# {{ ansible_managed }} +# +# Project Zomboid's own log files. These are separate from the container's +# stdout, which podman rotates itself via the k8s-file driver's max_size. +# +# copytruncate is mandatory here: the server holds these fds open for the whole +# life of the process, so a rename would leave it writing into an unlinked +# inode and the file would appear to simply stop growing. +# +# The Discord bot tails server-console.txt from a byte offset and resets that +# offset when the file shrinks, so a truncate under it is safe. +{{ zomboid_path }}/data/server-console.txt +{{ zomboid_path }}/data/Logs/*.txt +{ + copytruncate + daily + size 100M + rotate 3 + compress + delaycompress + missingok + notifempty +} diff --git a/ansible/roles/podman/templates/zomboid/server.ini.j2 b/ansible/roles/podman/templates/zomboid/server.ini.j2 new file mode 100644 index 0000000..6579c13 --- /dev/null +++ b/ansible/roles/podman/templates/zomboid/server.ini.j2 @@ -0,0 +1,439 @@ +{#- + Project Zomboid server config -- Sophie 42 preset. + + Vendored verbatim from https://github.com/GerDeathstar/sophie-pz + ("Sophie 42 Files.zip", uploaded 2026-07-31 == the `b42` release tag), + file Server/sophie-server-42-1.ini. + + Only the keys this deployment actually owns are templated -- credentials, + RCON, Discord, backup cadence, and the mod lists. Every gameplay setting + (PVP, safety system, safehouses, sleep, MaxPlayers, PauseEmpty, ResetID, + the welcome message) is left exactly as the preset author shipped it. + + Seeded once, then left alone: the deploy task uses force=false so the + server and admins can hand-edit this file between world regenerations. + Re-push it deliberately with -e zomboid_config_force=true. +-#} +{% set excluded_mod_ids = zomboid_mods_excluded | map(attribute='mod_id') | list %} +{% set excluded_workshop_ids = zomboid_mods_excluded | map(attribute='workshop_id') | list %} +# Players can hurt and kill other players +PVP=true + +# PVP is logged to admin chat +PVPLogToolChat=true + +# PVP is logged to file +PVPLogToolFile=true + +# Game time stops when there are no players online +PauseEmpty=true + +# Toggles global chat on or off. +GlobalChat=true + +ChatStreams=s,r,a,w,y,sh,f,all + +# Clients may join without already having an account in the whitelist. If set to false, administrators must manually create username/password combos. +Open=true + +# The first welcome message visible in the chat panel. This will be displayed immediately after player login. you can use RGB colours to chance the colour of the welcome message. You can also use < LINE>, without the space, to create a separate lines within your text. Use: \ This message will show up red! +ServerWelcomeMessage=Welcome to Project Zomboid Multiplayer! To interact with the Chat panel: press Tab, T, or Enter. The Tab key will change the target stream of the message. Global Streams: /all Local Streams: /say, /yell Special Steams: /whisper, /safehouse, /faction. Press the Up arrow to cycle through your message history. Click the Gear icon to customize chat. Happy surviving! + +# Display usernames above player's heads in-game. +DisplayUserName=true + +# Display first & last name above player's heads. +ShowFirstAndLastName=false + +UsernameDisguises=false + +HideDisguisedUserName=false + +SwitchZombiesOwnershipEachUpdate=false + +# Force every new player to spawn at these set x,y,z world coordinates. Find desired coordinates at map.projectzomboid.com. (Ignored when 0,0,0) +SpawnPoint=0,0,0 + +# Players can enter and leave PVP on an individual basis. A player can only hurt another player when at least one of them is in PVP mode - as shown by the unobscured skull and crossbones on the left of the screen. When SafetySystem=false, players are free to hurt each other at any time if PVP is enabled. +SafetySystem=true + +# Display a skull icon over the head of players who have entered PVP mode +ShowSafety=true + +# The time it takes for a player to enter and leave PVP mode Min: 0 Max: 1000 Default: 2 +SafetyToggleTimer=2 + +# The delay before a player can enter or leave PVP mode again, having recently done so Min: 0 Max: 1000 Default: 3 +SafetyCooldownTimer=3 + +# Min: 0 Max: 60 Default: 60 +SafetyDisconnectDelay=60 + +# Item types new players spawn with. Separate multiple item types with commas. Example: Base.Axe,Base.Bag_BigHikingBag +SpawnItems= + +# Default starting port for player data. If UDP, this is this one of two ports used. Min: 0 Max: 65535 Default: 16261 +DefaultPort=16261 + +# Min: 0 Max: 65535 Default: 16262 +UDPPort=16262 + +# Reset ID determines if the server has undergone a soft-reset. If this number does match the client, the client must create a new character. Used in conjunction with PlayerServerID. It is strongly advised that you backup these IDs somewhere Min: 0 Max: 2147483647 Default: 985847558 +ResetID=6953472 + +# Enter the mod loading ID here. It can be found in \Steam\steamapps\workshop\modID\mods\modName\info.txt +Mods={{ zomboid_sophie_mod_ids | reject('in', excluded_mod_ids) | join(';') }} + +# Enter the foldername of the mod found in \Steam\steamapps\workshop\modID\mods\modName\media\maps\ +Map={{ zomboid_map }} + +# Kick clients whose game files don't match the server's. +DoLuaChecksum=false + +DenyLoginOnOverloadedServer=true + +# Shows the server on the in-game browser. (Note: Steam-enabled servers are always visible in the Steam server browser) +Public=false + +# Name of the server displayed in the in-game browser and, if applicable, the Steam browser +PublicName={{ zomboid_public_name }} + +# Description displayed in the in-game public server browser. Typing will create a new line in your description +PublicDescription= + +# Maximum number of players that can be on the server at one time. This excludes admins. +# WARNING: Server player counts above 32 will potentially result in poor map streaming and desync. Please advance with caution. Min: 1 Max: 100 Default: 32 +MaxPlayers=32 + +# Ping limit, in milliseconds, before a player is kicked from the server. (Set to 0 to disable) Min: 0 Max: 2147483647 Default: 0 +PingLimit=0 + +# Items will not respawn in buildings that players have claimed as a safehouse +SafehousePreventsLootRespawn=true + +# Remove player accounts from the whitelist after death. This prevents players creating a new character after death on Open=false servers +DropOffWhiteListAfterDeath=false + +# All forms of fire are disabled - except for campfires +NoFire=false + +# If checked, every time a player dies a global message will be displayed in the chat +AnnounceDeath=true + +# If checked, every time an animal dies a global message will be displayed in the chat +AnnounceAnimalDeath=false + +# Loaded parts of the map are saved after this set number of real-world minutes have passed. (The map is usually saved only after clients leave a loaded area) Min: 0 Max: 2147483647 Default: 0 +SaveWorldEveryMinutes=10 + +# Both admins and players can claim safehouses +PlayerSafehouse=false + +# Only admins can claim safehouses +AdminSafehouse=false + +# Allow non-members to enter a safehouse without being invited +SafehouseAllowTrepass=true + +# Allow fire to damage safehouses +SafehouseAllowFire=true + +# Allow non-members to take items from safehouses +SafehouseAllowLoot=true + +# Players will respawn in a safehouse that they were a member of before they died +SafehouseAllowRespawn=false + +# Players must have survived this number of in-game days before they are allowed to claim a safehouse Min: 0 Max: 2147483647 Default: 0 +SafehouseDaySurvivedToClaim=0 + +# Players are automatically removed from a safehouse they have not visited for this many real-world hours Min: 0 Max: 2147483647 Default: 144 +SafeHouseRemovalTime=144 + +# Governs whether players can claim non-residential buildings. +SafehouseAllowNonResidential=false + +SafehouseDisableDisguises=true + +# Min: 0 Max: 2147483647 Default: 20000 +MaxSafezoneSize=20000 + +# Allow players to destroy world objects with sledgehammers +AllowDestructionBySledgehammer=true + +# Allow players to destroy world objects only in their safehouse (require AllowDestructionBySledgehammer to true). +SledgehammerOnlyInSafehouse=false + +War=false + +# Time in seconds before the war starts. Min: 60 Max: 2147483647 Default: 600 +WarStartDelay=600 + +# War duration in seconds. Min: 60 Max: 2147483647 Default: 3600 +WarDuration=3600 + +# Safehouse hit points limit. Min: 0 Max: 2147483647 Default: 3 +WarSafehouseHitPoints=3 + +# ServerPlayerID determines if a character is from another server, or single player. This value may be changed by soft resets. If this number does match the client, the client must create a new character. This is used in conjunction with ResetID. It is strongly advised that you backup these IDs somewhere +ServerPlayerID= + +# The port for the RCON (Remote Console) Min: 0 Max: 65535 Default: 27015 +RCONPort={{ zomboid_rcon_port }} + +# RCON password (Pick a strong password) +RCONPassword={{ zomboid_admin_password }} + +# Enables global text chat integration with a Discord channel +DiscordEnable=true + +# Discord bot access token +DiscordToken={{ zomboid_discord_token }} + +# The Discord chat channel name +DiscordChatChannel={{ zomboid_discord_chat_channel }} + +# The Discord logs channel name +DiscordLogChannel= + +# The Discord commands channel name +DiscordCommandChannel= + +# The Slack incoming webhook URL +WebhookAddress= + +# Clients must know this password to join the server. (Ignored when hosting a server via the Host button) +Password={{ zomboid_password }} + +# Limits the number of different accounts a single Steam user may create on this server. Ignored when using the Hosts button. Min: 0 Max: 2147483647 Default: 0 +MaxAccountsPerUser=0 + +# Allow co-op/splitscreen players +AllowCoop=true + +# Players are allowed to sleep when their survivor becomes tired, but they do not NEED to sleep +SleepAllowed=false + +# Players get tired and need to sleep. (Ignored if SleepAllowed=false) +SleepNeeded=false + +# WIP: Activating this setting may cause visual desynchronization of player positions. +KnockedDownAllowed=false + +SneakModeHideFromOtherPlayers=true + +UltraSpeedDoesnotAffectToAnimals=false + +# List Workshop Mod IDs for the server to download. Each must be separated by a semicolon. Example: WorkshopItems=514427485;513111049 +WorkshopItems={{ zomboid_sophie_workshop_items | reject('in', excluded_workshop_ids) | join(';') }} + +# Show Steam usernames and avatars in the Players list. +SteamScoreboard=false + +# Enable the Steam VAC system +SteamVAC=true + +# Attempt to configure a UPnP-enabled internet gateway to automatically setup port forwarding rules. The server will fall back to default ports if this fails +UPnP=true + +# VOIP is enabled when checked +VoiceEnable=true + +# The minimum tile distance over which VOIP sounds can be heard. Min: 0.00 Max: 100000.00 Default: 10.00 +VoiceMinDistance=10.0 + +# The maximum tile distance over which VOIP sounds can be heard. Min: 0.00 Max: 100000.00 Default: 100.00 +VoiceMaxDistance=100.0 + +# Toggle directional audio for VOIP +Voice3D=true + +# Min: 10.00 Max: 150.00 Default: 70.00 +SpeedLimit=70.0 + +LoginQueueEnabled=false + +# Min: 20 Max: 1200 Default: 60 +LoginQueueConnectTimeout=60 + +# Set the IP from which the server is broadcast. This is for network configurations with multiple IP addresses, such as server farms +server_browser_announced_ip= + +# Players can respawn in-game at the coordinates where they died +PlayerRespawnWithSelf=false + +# Players can respawn in-game at a split screen / Remote Play player's location +PlayerRespawnWithOther=false + +# Governs how fast time passes while players sleep. Value multiplies the speed of the time that passes during sleeping. Min: 1.00 Max: 100.00 Default: 40.00 +FastForwardMultiplier=40.0 + +# Safehouse acts like a normal house if an owner of the safehouse is connected (so secure when the owner is offline) +DisableSafehouseWhenOwnerConnected=false + +# Players can create factions when true +Faction=true + +# Players must survive this number of in-game days before being allowed to create a faction Min: 0 Max: 2147483647 Default: 0 +FactionDaySurvivedToCreate=0 + +# Number of players required as faction members before the faction owner can create a group tag Min: 1 Max: 2147483647 Default: 1 +FactionPlayersRequiredForTag=1 + +# Disables radio transmissions from players with an access level +DisableRadioStaff=false + +# Disables radio transmissions from players with 'admin' access level +DisableRadioAdmin=true + +# Disables radio transmissions from players with 'gm' access level +DisableRadioGM=true + +# Disables radio transmissions from players with 'overseer' access level +DisableRadioOverseer=false + +# Disables radio transmissions from players with 'moderator' access level +DisableRadioModerator=false + +# Disables radio transmissions from invisible players +DisableRadioInvisible=true + +# Semicolon-separated list of commands that will not be written to the cmd.txt server log. For example: -vehicle. Inputting * means do NOT write any vehicle command. Inputting: +vehicle.installPart means DO write that command +ClientCommandFilter=-vehicle.*;+vehicle.damageWindow;+vehicle.fixPart;+vehicle.installPart;+vehicle.uninstallPart + +# Semicolon-separated list of actions that will be written to the ClientActionLogs.txt server log. +ClientActionLogs=ISEnterVehicle;ISExitVehicle;ISTakeEngineParts; + +# Track changes in player perk levels in PerkLog.txt server log +PerkLogs=true + +# Maximum number of items that can be placed in a container. Zero means there is no limit. (PLEASE NOTE: This includes individual small items such as nails. A limit of 50 will mean only 50 nails can be stored.) Min: 0 Max: 9000 Default: 0 +ItemNumbersLimitPerContainer=0 + +# Number of days before old blood splats are removed. +# Removal happens when map chunks are loaded. +# Zero means they will never disappear Min: 0 Max: 365 Default: 0 +BloodSplatLifespanDays=0 + +# Allow use of non-ASCII (cyrillic etc) characters in usernames +AllowNonAsciiUsername=false + +BanKickGlobalSound=true + +# If enabled, when HoursForCorpseRemoval triggers, it will also remove player's corpses from the ground. +RemovePlayerCorpsesOnCorpseRemoval=false + +# If true, player can use the "delete all" button on bins. +TrashDeleteAll=false + +# If true, player can hit again when struck by another player. +PVPMeleeWhileHitReaction=false + +# If true, players will have to mouse over someone to see their display name. +MouseOverToSeeDisplayName=true + +# If true, automatically hide the player you can't see (like zombies). +HidePlayersBehindYou=true + +# Damage multiplier for PVP melee attacks. Min: 0.00 Max: 500.00 Default: 30.00 +PVPMeleeDamageModifier=30.0 + +# Damage multiplier for PVP ranged attacks. Min: 0.00 Max: 500.00 Default: 50.00 +PVPFirearmDamageModifier=50.0 + +# Modify the range of zombie attraction to cars. (Lower values can help with lag.) Min: 0.00 Max: 10.00 Default: 0.50 +CarEngineAttractionModifier=0.5 + +# Governs whether players bump (and knock over) other players when running through them. +PlayerBumpPlayer=false + +# Controls display of remote players on the in-game map. 1=Hidden 2=Friends 3=Friends and nearby players 4=Everyone Min: 1 Max: 4 Default: 1 +MapRemotePlayerVisibility=1 + +# Min: 1 Max: 300 Default: 5 +BackupsCount=10 + +BackupsOnStart=true + +BackupsOnVersionChange=true + +# Min: 0 Max: 1500 Default: 0 +BackupsPeriod=30 + +# Disables vehicle towing +DisableVehicleTowing=false + +# Disables trailer towing +DisableTrailerTowing=false + +# Disables burnt vehicle towing +DisableBurntTowing=false + +# Path to the file with the list of words to be prohibited. Each word must be on a separate line +BadWordListFile= + +# Path to the file with the list of words that should be allowed, even if they contain bad word. Each word should be on a separate line. +GoodWordListFile= + +# What to do with the sender of a bad word in the chat: 1 - ban, 2 - kick, 3 - record the violation in the database, 4 - mute +BadWordPolicy=3 + +# The symbol or piece of text that will replace the bad word +BadWordReplacement=[HIDDEN] + +# Disables safety system anti-cheat protection. +AntiCheatSafety=2 + +# Disables character speed anti-cheat protection. +AntiCheatSpeed=2 + +# Disables character no-clipping anti-cheat protection. +AntiCheatNoClip=4 + +# Disables character hit anti-cheat protection. +AntiCheatHit=2 + +# Disables packet exception checks anti-cheat protection. +AntiCheatPacketException=4 + +# Disables player permissions anti-cheat protection. +AntiCheatPermission=2 + +# Disables player XP anti-cheat protection. +AntiCheatXP=2 + +# Disables safehouse anti-cheat protection. +AntiCheatSafeHouse=2 + +# Disables player anti-cheat protection. +AntiCheatPlayer=2 + +# Disables checksum anti-cheat protection. +AntiCheatChecksum=2 + +# Sets the multiplayer update period in seconds. Statistics is disabled if value is 0. Min: 0 Max: 10 Default: 1 +MultiplayerStatisticsPeriod=1 + +# Disables scoreboard. +DisableScoreboard=false + +# Hides admins in the player list. +HideAdminsInPlayerList=false + +# Sets the limit for processing network packets from each client on the server. Min: 100 Max: 1000 Default: 300 +MaxPacketsPerSecond=300 + +# Shows player character coordinates in the lower right corner. +ShowCoordinates=false + +# The worldgen seed used to generate the world. +# If you want to change this, put a new value in and delete map_worldgen.bin in your save directory. +Seed=DMCERZSTKtuzgukR + +UsePhysicsHitReaction=false + +# Min: 64 Max: 1024 Default: 200 +ChatMessageCharacterLimit=200 + +# Min: 1 Max: 30 Default: 3 +ChatMessageSlowModeTime=3 \ No newline at end of file diff --git a/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 b/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 index d0d4696..d37cb23 100644 --- a/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 +++ b/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 @@ -6,7 +6,7 @@ set -e LOGFILE="{{ podman_home }}/.local/share/volumes/zomboid/logs/world-reset.log" TRIGGER_FILE="{{ podman_home }}/.local/share/volumes/gregtime/data/zomboid-reset.trigger" -SERVER_NAME="{{ zomboid_server_names[zomboid_server_mode] }}" +SERVER_NAME="{{ zomboid_server_name }}" SAVES_PATH="{{ podman_home }}/.local/share/volumes/zomboid/data/Saves/Multiplayer/${SERVER_NAME}" DB_PATH="{{ podman_home }}/.local/share/volumes/zomboid/data/db/${SERVER_NAME}.db" diff --git a/ansible/roles/podman/vars/zomboid_sophie_mods.yml b/ansible/roles/podman/vars/zomboid_sophie_mods.yml new file mode 100644 index 0000000..aa4ff8b --- /dev/null +++ b/ansible/roles/podman/vars/zomboid_sophie_mods.yml @@ -0,0 +1,562 @@ +--- +# Sophie 42 modlist -- vendored verbatim from the upstream server preset. +# +# Source: https://github.com/GerDeathstar/sophie-pz ("Sophie 42 Files.zip", +# uploaded 2026-07-31, identical to the `b42` release tag) +# Origin: Server/sophie-server-42-1.ini, keys `Mods=` and `WorkshopItems=` +# +# Kept as lists rather than the semicolon blobs the INI uses so that a Sophie +# update produces a reviewable diff. `templates/zomboid/server.ini.j2` joins +# them back with `;` after subtracting `zomboid_mods_excluded`. +# +# ORDER IS SIGNIFICANT for zomboid_sophie_mod_ids -- it is the mod load order. +# Preserve upstream ordering exactly when re-vendoring; do not sort. +# +# No `\` prefix: Build 42 required one only during its unstable period and +# rejects it on 42.20+. + +# Mod IDs (from each package's mod.info) -- the `Mods=` server key. +zomboid_sophie_mod_ids: + - "ModLoadOrderSorter_b42" + - "damnlib" + - "YAPZLib" + - "ChuckleberryFinnAlertSystem" + - "errorMagnifier" + - "ZomboidPaperAPI" + - "MoodleFramework" + - "moodlesinlua" + - "NeatUI_Framework" + - "HBVCEFb42" + - "KATTAJ1_ClothesCore" + - "SpnOpenClothBase" + - "TombBody" + - "isoContainers" + - "PROJECTRVInterior42" + - "LargeProgressIndicator" + - "CleanUI" + - "MiniHealthPlus" + - "BravoItemDetails" + - "DetailedDescriptionsForOccupationsAndTraits" + - "MutiesContextMenuIcons" + - "ItemCondition_KingEJ" + - "SPNCC" + - "SPNCCDetails" + - "SPNCCDetailsHD" + - "SeedSeasonIndicator" + - "NeatUI_Hairstyler" + - "Neat_Building" + - "Neat_Building_AddonXP" + - "Neat_Crafting" + - "Neat_Crafting_AddonXP" + - "DynamicMoodles" + - "devcattpixelmoodles" + - "redrawnmoodles" + - "PMResurrection" + - "PlainMoodles_by_Slobodskoy" + - "quarterbordermoodles" + - "SimpleMoodleIndicators" + - "v1centesmoodles" + - "v1centesmoodlesbeta" + - "SandboxSettings" + - "SimpleOverhaulTraitsAndOccupations" + - "BeyondTen" + - "HasResearch" + - "WorkingKnowledge" + - "SkillRecoveryJournal" + - "M13ReadingTweaks" + - "P4HasBeenRead" + - "P4PickingMeister" + - "P4TidyUpMeister" + - "KillCount" + - "CausaMortis" + - "KI5campers" + - "KI5trailers" + - "TradingTrailer" + - "49powerWagon" + - "59meteor" + - "63beetle" + - "63Type2Van" + - "65banshee" + - "66pontiacLeMans" + - "67commando" + - "67gt500" + - "68firebird" + - "69camaro" + - "69charger" + - "69fordMustang" + - "69fordMustangExtra" + - "69mini" + - "69mini_ItalianJob" + - "69mini_PitbullSpecial" + - "70barracuda" + - "70chevelle" + - "70dodge" + - "70fordEscort" + - "70roadRunner" + - "73fordFalcon" + - "73fordFalconPS" + - "73nissanGTR" + - "75grandPrix" + - "76chevyKseries" + - "76chryslerNewYorker" + - "77firebird" + - "78amgeneralM35A2" + - "78amgeneralM35A2extra" + - "78amgeneralM49A2C" + - "78amgeneralM50A3" + - "78amgeneralM62" + - "78lamboCountach" + - "79camaro" + - "80manKat1" + - "81deloreanDMC12" + - "82firebird" + - "82jeepJ10" + - "82jeepJ10t" + - "82oshkoshM911" + - "82porsche911" + - "84buickElectra" + - "84cadillacDeVille" + - "84corvette" + - "84jeepXJ" + - "84merc" + - "84oldsmobile98" + - "85buickLeSabre" + - "85chevyCaprice" + - "85chevyStepVan" + - "85chevyStepVanexpanded" + - "85oldsmobileDelta88" + - "85pontiacParisienne" + - "86chevyCUCV" + - "86fordE150" + - "86fordE150expanded" + - "86fordE150pd" + - "86oshkoshP19A" + - "87buickRegal" + - "87chevySuburban" + - "87fordB700" + - "87toyotaMR2" + - "88chevyS10" + - "88toyotaHilux" + - "89defender" + - "89dodgeCaravan" + - "89fordBronco" + - "89trooper" + - "89volvo200" + - "90bmwE30" + - "90fordF350ambulance" + - "90pierceArrow" + - "91fordLTD" + - "91fordRanger" + - "91geoMetro" + - "91lexusLS400" + - "91nissan240sx" + - "91range" + - "92amgeneralM998" + - "92amgeneralM998extra" + - "92fordCVPI" + - "92jeepYJ" + - "92jeepYJJP18" + - "92nissanGTR" + - "93chevySuburban" + - "93chevySuburbanExpanded" + - "93fordElgin" + - "93fordF350" + - "93fordTaurus" + - "93mustangSSP" + - "93townCar" + - "99fordCVPI" + - "ReactiveSE" + - "HereGoesTheSun" + - "RainCleansBlood" + - "CheckthePapers" + - "DeadMansDossier" + - "KnoxDetectionKit" + - "ZVirusVaccine42BETA" + - "LifestyleHobbies" + - "GuitarMusicAddon" + - "DeltaSeries" + - "AP" + - "AutoReload" + - "AutoTailoring" + - "better-auto-mechanics" + - "CaffeineMakesSense" + - "Drink_Smart" + - "dustinguished_bolt_cutters" + - "FasterHoodOpening" + - "FWOFitnessWorkoutOverhaul" + - "FWOBenchPress&Treadmill" + - "KeepRadioOnVanillaFriendly" + - "MoreUsesForLightersAndMatches" + - "NoLighterNeeded" + - "OCsPacking" + - "SmarterStorage" + - "STA_PryOpen" + - "stanks_suicide" + - "SwapIt" + - "throw-your-bag-across" + - "UseItemsWhileWalkingB42" + - "OpenAllContainers" + - "RebalancedPropMoving" + - "RepairAnyClothes" + - "ReducedWeightWalkieTalkies" + - "WashFix" + - "w_betterwringing" + - "DRAW_ON_MAP" + - "FirstAidVHSTapes" + - "NepCanteenSlot" + - "TacHold AR" + - "TacHold Pistol AR" + - "ShelterHold_Beehive" + - "Ladders42131" + - "JWJ" + - "ClothingLine" + - "ComputerModkum" + - "Buttstroke" + - "CVI" + - "CVLS" + - "FunctionalAppliances2" + - "JB_BugsInLights" + - "LWBetterElectronics" + - "MoreDamagedObjects" + - "PIP" + - "playable_pool" + - "PSR" + - "RepairWallCracks_B42" + - "SomewhatWater" + - "Snowman" + - "SkillBookExpansionB42" + - "UseulTents" + - "WorkingVending" + - "Video_Game_Consoles" + - "VGC_Addon_NESGames" + - "VGC_Addon_SEGAGames" + - "VGC_Addon_SNESGames" + - "VGC_Addon_SNESGames2" + - "TVRadio_ReInvented" + - "NewMusic" + - "NewMusicG70s" + - "NewMusicG80s" + - "NewMusicG90s" + - "NMGreatestHits" + - "NewMusic_OrchestraMix" + - "Project_Cook" + - "B42Horticulture" + - "SKITTLE_LongTermPreservation4220" + - "VanillaFoodsExpanded" + - "SapphCooking_B42" + - "Makedriedfruit" + - "Makedriedvegetable" + - "Makefruitinjar" + - "Mushroomjar" + - "ServingPlatesB42" + - "Edwin'sCannedTent" + - "Edwin'sCannedTobaccoKit" + - "Edwin'sSurvivalTabsMod" + - "dustinguished_cleaning_wipes" + - "ExtraBombs2" + - "ammomaker" + - "B42Survival" + - "SWMG" + - "MarzGuns" + - "LEGION18" + - "SpnOpenCloth" + - "SpnCloth" + - "FH" + - "SpnHair" + - "VanillaGearExpanded" + - "ArmoredVests" + - "ArmoredVestsPatch" + - "AliceGear" + - "[J&G] Firefighter Uniform" + - "[J&G] SWAT Uniform" + - "[J&G] Trauma Responder Uniform" + - "[J&G] Desert Multicam Uniform" + - "DarkWpnSlings" + - "GanydeBielovzki's Frockin Splendor!" + - "GanydeBielovzki's Frockin Splendor! Vol.2" + - "GanydeBielovzki's Frockin Splendor! Vol.3" + - "GanydeBielovzki's Frockin Splendor! Vol.4" + - "GanydeBielovzki's Frockin Splendor! Vol.5" + - "GanydeBielovzki's Frockin Shirts n Ties" + - "GanydeBielovzki's Frockin Wiseguys" + - "GanydeBielovzki's Frockin Stompers! VFR" + - "CorvusNVG" + - "AccCamos" + - "AccCamosPeriodPack" + - "TombBodyCompat" + - "TombBodyTex" + - "TombBodyCustom" + - "ProjectArcade" + - "BCR" + - "DG_MIVehicles" + - "WayMoreCars" + - "VMZNEW" + - "VVR" + - "RealisticDash" + - "GasPumpIndicator" + - "immersive_hotwire" + - "NepHighBeams" + - "TaillightsAndStoplights" + - "VehicleDoorsHotkey" + - "VehicleRepairOverhaul" + - "VehicleSalvageOverhaulB42" + +# Numeric Steam Workshop page IDs -- the `WorkshopItems=` server key. +# These are what SteamCMD actually downloads. +zomboid_sophie_workshop_items: + - "3423660713" + - "3171167894" + - "3624971238" + - "3077900375" + - "2896041179" + - "3155647374" + - "3396446795" + - "3395171770" + - "3508537032" + - "3610677934" + - "3470422050" + - "2812326159" + - "3429790870" + - "2625625421" + - "3543229299" + - "2926455909" + - "3437629766" + - "3710913197" + - "3477237184" + - "3387957272" + - "3101668503" + - "3641048285" + - "3414634809" + - "3734639991" + - "3760534563" + - "3536052310" + - "3540503606" + - "3502080466" + - "3674800555" + - "3417051694" + - "3386486141" + - "3569718104" + - "3772979228" + - "3391323469" + - "3402171609" + - "3389609367" + - "3386906181" + - "2840805724" + - "3765241705" + - "3567695139" + - "3717099183" + - "2503622437" + - "2776874515" + - "2544353492" + - "3422220305" + - "2769706949" + - "2553809727" + - "3711044244" + - "3670064951" + - "3330403100" + - "3572122233" + - "2900580391" + - "2772575623" + - "3005903549" + - "3041122351" + - "3566868353" + - "3447272250" + - "2478247379" + - "3026723485" + - "3258343790" + - "2991201484" + - "3631989559" + - "3756938756" + - "2937786633" + - "2913633066" + - "3766571591" + - "2873290424" + - "3670063857" + - "3642935062" + - "3490370700" + - "3743371090" + - "3213391371" + - "3161951724" + - "3730833846" + - "3346905070" + - "2799152995" + - "3726526329" + - "3703948448" + - "3248388837" + - "3253385114" + - "3320947974" + - "2886832257" + - "2618213077" + - "3379334330" + - "3596903773" + - "3592777775" + - "3684254299" + - "3409287192" + - "2805630347" + - "3601417745" + - "3418252689" + - "3413704851" + - "3614034284" + - "3418253716" + - "3413706334" + - "3428008364" + - "2870394916" + - "2566953935" + - "3226885926" + - "3196180339" + - "3110911330" + - "3052360250" + - "2886832936" + - "3435796523" + - "3570973322" + - "3034636011" + - "2886833398" + - "2932549988" + - "3292659291" + - "3110913021" + - "2952802178" + - "2942793445" + - "3366300557" + - "3539691958" + - "3008795514" + - "3770890864" + - "3504401781" + - "2409333430" + - "2642541073" + - "2962175696" + - "3287727378" + - "2846036306" + - "3152529790" + - "2969343830" + - "3073430075" + - "3088951320" + - "3001592312" + - "2932547723" + - "2971246021" + - "3656190498" + - "3618557184" + - "2956146279" + - "3580513066" + - "3675740871" + - "3688879406" + - "3615135168" + - "3403870858" + - "3412944806" + - "3660235667" + - "3766508989" + - "3389448389" + - "3388183573" + - "3635856965" + - "3682557825" + - "3447775367" + - "3671176591" + - "2584112711" + - "2940354599" + - "3558422176" + - "3533994661" + - "2714198296" + - "3626823538" + - "3290232938" + - "3579640010" + - "3426448380" + - "2366717227" + - "3391902125" + - "3615422211" + - "3465040406" + - "2699828474" + - "2142622992" + - "2981090458" + - "3460812542" + - "3408740647" + - "2804531012" + - "3153010942" + - "3393080905" + - "3677017550" + - "3680633169" + - "3596827035" + - "3629835761" + - "2868828908" + - "3282215361" + - "3725497089" + - "3394044313" + - "3749026793" + - "3719237374" + - "3042138819" + - "3717902500" + - "2999183635" + - "3413150945" + - "3739173520" + - "3716934959" + - "3725311427" + - "3684808606" + - "3582960654" + - "3669451917" + - "3625874308" + - "2934155949" + - "2831786301" + - "3413237147" + - "3423725989" + - "3408186716" + - "3488113291" + - "3420581050" + - "3739256725" + - "3765077081" + - "3765079521" + - "3765670104" + - "3751364201" + - "3760471726" + - "3490188370" + - "3650168851" + - "3774789651" + - "3577903007" + - "3409143790" + - "3417502641" + - "3418061837" + - "3432006285" + - "3416833689" + - "3399320470" + - "3453369692" + - "3455296935" + - "3453175422" + - "3755185651" + - "3652008781" + - "2788256295" + - "3402516345" + - "3722064198" + - "3722134990" + - "3665548194" + - "3660382016" + - "3557111695" + - "2684285534" + - "2447729538" + - "2463184726" + - "3401134276" + - "1962761540" + - "3610005735" + - "3521263771" + - "3457969588" + - "3443982326" + - "3299457564" + - "3307376332" + - "3411888105" + - "3769335201" + - "3431256608" + - "3475347500" + - "3635394848" + - "3453676250" + - "3538760023" + - "3736813592" + - "3454414190" + - "3431734923" + - "3645980077" + - "3162566044" + - "3520758551" + - "3436499337" + - "3423424077" + - "3635591071" + - "3755993986" + - "3653092321" + - "3438126404" + - "3687394815" + - "2290459371" + - "2757712197" diff --git a/ansible/vars/vault.yml b/ansible/vars/vault.yml index 9851f47037336cb9accded5fa09ebd9c9c999780..e3d5a15fb9a3bd18efd77a84e2a10faeb824070f 100644 GIT binary patch literal 34461 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ℑ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 F-P#WWBc`r+S+_wR14 zKkHvD3hi@;xTf4xD%n#QB@ZpJLic0TB15S-%N`hR)i(@}Wy1j$1;3t57r7!Jc93lN z8WZK81X7RvaIXv)9-zI_T$@!r7*W3&lHVojd}I<6Cop^ZImJQufd|{WxyA{yx%ND& zF3J?h)??1oT5@lR$6muSPQ)l6jTFR*a0kIDRtvX&xK1-8f7uFT!Y@_OYho-Lj9D%t zrQuXqrpwCSiOeLu?`wX~J8NS#hk0@r`3_{}ub5fq3p+f@fZ|%rYE7f~J!obvKm*hG z=n|Em8b~=D5Pd(7K@I4q8rtpNEQHzse;4)oscvL-uN44Ea~_|OL1xg&lq984$!sQn z-=*^hjJ;QJQ20*MR8_P!gvxPJ)&(E*3!W`|>nzPgC-%PkxX10CaGFFix3gf*#jo6( zZc)~dMO>@Nji;jWhoO}!R(#<)IZdR2ru`1!hMfu5*@L7}I8am>0I;vn0M;aBn7|jx=1mh{pciGC{IS)E-voC`hx$To(O69(cFgSaN}? zLSJ%sKGBprKI=bddiSP5V&B<7p`Sv!Y#{*#w zCni}~$65L21jp)5!&Q)WV!#Ao2K%B{Y;62S`++ZU$X>g%b(ET)!PVtYA&aR0HK?!~ zFh1m$lSF&ZxGZOxljz)6j_a!fy-BkT z)baZFwE-O8Nvw}dcT|J-g}c~(1{@IJywr2VH72#|mRm&L8=R3UV|St$&^Dj_^kV-v zhIc72q~y)SALPk16U9;A&mFQ;5 z_Vj9I0;d&!Tv)HXe@EfmNX-9Zl);v9Z|UyMqJvatAs)YXq-NuQ6op&Wqc_A4!c54B z>(9m41-vBa(`IAKzW}5QfXj5G<-wdN8Qnt&b*1+R#rfFn>pzg*eAu1rNe)H4C-Dmj z{8BFcB33104fPoHcW9q8Jvqye;7xV`ADzr7p>uMoBifcbZPAkZE=B;V#0*a3)u!h0 zXFD! zzZL!!7yV1~LwyGWEkmRC$z{EVyR{PDtwk!zq#X&O5D&rf{Tj{5UDrcu7=miSW>lff zewJ(?m+0{xAW6DF5S`v3HuYD_f1=G5%;-ziry1*B2Tjo$)b}t;s#9hR;T()D00p&0 zLqdu819v;|mXJVFCKU+x6&r$CetGmo%d(31drHzXoUw;GyNk)RG<56QI{I_Obj~9D z6U?yI9?_6xnBC&_1~dm`L}vkqbTOO}{Ro!gdoLfjI~0JilBOcxJAQ5ulCoyCj3~1;pe4ZEtiGzHQrEp}UDy+s`ZTNnzRmRF@+~ zheG2SUPSg^!3GV>h#lUTWyC3B&C+w#+R8!PJ=$ffwCdYSR83$;@foa3Mk_|&yfS{O z^Q8iJ^Fl9`bogPrvid)@{wB@d(+>2;^zl7LrFdXv+p=p_kE)$u6w6FZ9cH%mjLh9_ z+ZAJW0E#VDXGNl)1r5vm1Cdnnf69x7nnM2=?suE7o|?%BUk8sc5y+2>y~AP6@~L0o zm-Q$cv?^G8vQqK3q^%9K{2or93!UeVqUu8x-sKDWijXCp-`t#J-&>x~Ri!H2+c1mWTqs_v*2~?I7fD z-J}l^D9TR zNSvh(1>tR-4c7%K;5{cbna7_Zp+5^=NO0gWsT!YCq8`BSf1Q=Fo5*3pFbc6goA@9o z3C#x^;0=xv;k-Fk5d1ICF#exTcJMqUDy{2u`(--=DVKzb)`1nH)-L`5fimfwp^#33 zG2zUt86+niXBRsEi2Qpln^sUlSWDIFoQ)o_6CsPg+qDg{m9idPUun{B>DJ>KKZk`^ zPZ`kbs8qzj7OJPu8DU*BmQ>!EVw|KRox+3+)j>DH)O23th5 zH?+JsO~uUvs!&xXYkauG{lk?jq!m8(7}l*H&~_F=+1jwB)_KBlyMcXCws8rhRn~4Y z^|b8N$5yTp>PH7esJA^muM=;#6xi04W}hqbBY!>0@`=_{v^L4!cVtvyG0!lm$z3`A zd@$(-Ndu;L(}HcRX{Rp@-d^s-;DP>&ornZR6P1Mbx&nr99C(x$ln{y(j5BoWjqBwf z4Elt!Cd&oL)fQ-kLe7d<@fD7h*S>N$%0Qw3w)PSkZ;a&uyS%|V*hrJj)<4$nlhWD7 zeiku^n|ruov7kwVosxN}YZJSN@jh~+&hftGgFJy>+X56Lieka#qkklvvJ(AeVXY?f zGFhFvcXT4JZYkFadUi;tAsujs=`CXY#wAy?&6yi_tl}fhguD0az#+c0pW7SitvaoK z3H}lGpdg4{V6ppPS~xZvv3o;ZE_!7(Z3EUuT6W3=b?sdy>eUB=LARVil9i~naK=gf zug)QJDewiNJfVGe>@}T4v1l#rA9(4muS?$`MjH@MiWmk`u2+kxCxv5#Kski`hm=8C zDtakkD=|obje_=Y^}k(T;(qT?q_6=a8k+MOT<3OMvoYYPY!T|@Rg5FW45N?KsdzH= zhgtUSFFE->Rscth+y<3gT@3@ND%Tf9IhwO~;wn{Qy2);|qIlZGw#QW1$s=><3+M-` zcP})$33Zi_yO9CT&`nm+xCmer3&B68Wws90Ys^%_yCJvEkntC%Z4pPtD1%xUi=Kj} z6s)4wTe+mO{5>7jscB8__Ix|qRKPF%SxsIFd$?w`SvHW+RVbv=5{c@=ih%DZ$t)T! ztv9M>xD^G}BoYyBj;;ZMqLrmFJwU@!_T6V)B;yJ(M7tQm478^&1Q3|oXeo5M14=F_tC7Wh>B2;VV@vZ!%t>635$|1 zcwA(XvMF-{M=1bWV5aGxnw~tb8bHerpcQ~9`b@i!lu6()AbvP}h4Vb&9&kaq6t^v&2uQq|8LluW(^>`b!V^s%7V-*} z+!N$P)yCFzMX|DKmYJRcAr)cRukl!-w1IkC5aP#;3*WtKg^}<}oy#B6qrHH61_P!} zYz@0TMC99I2;$7)$>FWgsQirZ1fn*kX_iHT!0U3&6Xi$Hl>RnpB-~L{CrIB04GIt}RhlJ__@4~+uc2XaLZ_tta7KK?+oUa6fij8!<0B;~Wo6U3dUe@T+dZC*+SS{v&ZlBuM zi8Z4dY>>&r);1O=0iao0qTpY>zj6N3(FaXi)ALDA7Cy>G1O%PV(RbD?(mX7i0Y!wx zmmZO1FcxJ|T#~k27I%^?%tePU&zMvpGMC!Rnj&}R|7Y#ok$6Dk!VLj^2HX@0JdVY@ zIc)sc{6xjZ1MI;s`tE&Q7~j|Bt}tjv2{rYmgk6;)2AKQOF<%wW`#S~bLQ?7pu*!Eo zqJRs`0z^{9f3V8qhl40w5ohQ=E!-SspBO*>C@bdu2VAz-cS!Q~)3a(%av=w2voQ-` zyeF?RFlONUO&T$7)s|WOMqFm`I}YB+b-g%#h6iV@1wPUfX_KU=yRJY=Q8geD1YH8v}oC^0c+mj7zpp4;6}~F zJg);ayAvc5qPlI9G2#;N_O{mg_C}qLESLV9>M}jR#4+kl=q<88pKaBiAb_vWlk9vqx+x70z1rVHMtD z%Ncpx6{13yQ2;ig&fS3w2o$Hy1_V%kqy{9j7e6i7^hK+Kwc+8wZfhBv1nZ?7+Ryg~ai>No7QvK7QRA1|@ zy23~aPr!K~3#f*crn}4V>zt%yYRi2OC3PQawsb{@BqrQZl@646fF8R-`8w;NS07Hr zH)Z;yam<4k@<`mYEHW_<{I*BoBQ7WlMfXq>y+VW)kO0G332t{K6tJ|7Xr%tQt57w+ z)|Ato%Ant!-*Jb-Gp?&_kQEy%)GcF+WWAwFWECX=Vv7FAV-dYf*ll5x^P7W!fOiKR z`VS21#i2NT?ySL#Jw-znlh?_Xs^A6%g>g2Ep7E#+smCcO8>N(^LA45mk5>;DL2WvDZ;gtNqCJQk4DDy)0n&p(M+#p|hlez2)azgF&c(|&tExKaG z%vtbo10Pw0(Pb6n1A&x7!AQPVKQS4In^3mDy$_hpZf}Aw@5Bog^Z(b0l+XJ~1~%NY zozWq*a@v!059XsnjMZxyKppr@cmZ9HXtA=ga2Admk4Q}d;zDLL zYNe@&DTNVyE6`>|@0)+a(EQo_97v)u#jTJ*rOQEpT?IwA#Bmd66VQ zC=YMcv`9stgV3vl)#gq><>)efovxQ@+T@SNyZ{S%efnsp5GxC!J+XrT{K8oOqYM~4 zE$U5MjQ6-YypSV$=&drrc2tOat+nK4(R`YMz8dh)NGjWuVb@NM8Z>bekr{0=$U{;9 zd0U7=-KF9JC0Se|T)fT+*`7Fcm_BCR=rMnM~QbzCXzaLeLuKqI$-R zV|m@zSyqD*9{I<3`NP~wF4#c>%qCl}EHHJye@M#)7ygW3g~bd{m2##}^pQ9mQXwcM)UkeaK{ z-T}9pq@sw<a(T8g`4>D_6ubm1T9A3B&ve zYjE4v?~=tk8vxpR;=1c|zxEBg7JWD$rXceSL#Iy-YN1uAJF2vZv?R|OGK=C#rA$91 z54>$!B+77=)*Vut?o65M#7BC-LnBp_(F|CPZUM{p{>H$n-+m`GHk?4O0c!D}KZA>l3Pcyl^RlS1vrVezBDW z+nE-y3>M_FCK3mkQ+9f%dYUukcc%Wanu`nzR!o)suUJeqJAbEXoC}gI3Z1xHG+5nG zY$MR7m0yfCc&4MZ&FZ&DSZEx8l%MO}k8l1c2%P@G9825{YLSbhy_T!WkNW5A{@jM4 z<1Jt&YidQR`Jd4Nw0)YQ>DU3lw`bWXdbzfb12IIQ>gElED7FCh)2BpW!~pS$fcQux47UU%lY9FtP9*Qj2LA9> zpGXlhS7^F7q9#VoAKpAGLnA(&imzr}mTxn*o(G&#BxDxp#UaM2G-nkE981%|0+8UT6YFBCY6jm)Cu8NQw4f=( z-#c`Rn$I6Jl!Ce0hPEQ-%mK7%tUbHZg=SP7&P(3h#=PLUUEefspa!)dIh3{e1Zo9? z|9yg>&K1ay^ov6-fjC)N=okmrn@}p5DB=?Tts*dfJobHTpPQHf2QRbwoUxSs6jy9< z_E)i>M8D$>Cc-(@ODcVZmHdzJmbezwQNPrIrH!qYI3-ABEEWW&r7w-|;S@&zwS+d6 zQ_qipwXyA(=|x%Ktgj3+Ut4!8E$jQKyQk9EYWf?0#s4tS$|zbHRP50u2PHdShWt zzn@=L!Yg;=RM@K%DKZo04J+=n!bWHmtAr5p-i}@TJem zA6qMW;o7J0Z@K)Ra3GSA>+VnDEJEQhsR*uA=8dygi+U?;6GtR`@zw^>X|~yKi)f9fvh1AH^k=dU zXbwHcmAcLlF1B&w7W%X9YTVhI z2l4iC5%!X(FVRADt!+Y@5%YHJZ~vHo-`zOqHJ~x!#1ydlCkopX3jZr=wgm1(4n_5n z3jB^sfFemqAJzfdL5&{$ua2Tb1+8tM6gK-31`e6wniCO|wHsqv@Z^?xXqz~tVL$EuHlC&Ae8shDSzt|KT-lt^Oi zsL1GfEI!R?%~@RpRx&`NDmOVk-^=?o!`0 z#=fkJYs=M+90aV^ROFsZ`Ypp_aN)9$cBL|zG^KA;w|LPR&=Em0$6Eh$hD6fY$;7g~ z*DdsudLSs+f_NoGEGPld7o*f7gUC^n-$GuGn3z3QYTFGGk+jg%?M-e+#zKRvoy5va zptxGG)R;2X?|W+xAY-L2H?cAQI?Cn7NvllxV{9qAlr+ zg?rG6=aH(vQ?rdJB?eKg)f1T}Fb59uU1f53pAnnrid)O+0PacQEwDS58qtPd+GJYZ z;&V!~BuafU&kjg;R++&T1liv2Oc^|m&PJGbaW=X)_lp$1=EvFNkIGaJB*cmEe&BvnZ{Ti>gq+tQBf?J3H6Uvi}>^<7|P z17+dw=p-|0Hc-=@2iIifpPWEcpq9<%O)O`{^WUJCjGrfzdu(n5O>L-|A9c3XbWiM& zP+}dA2p=XB+`&h&^YV=d zYZPN9laPxl6r`A3dBuJDiDsN1?A}^wAJG6I%=&Io zd2!-N(NdW<7fs2mlCiPlS#8w3NyF|nju*vC-^3KdoX3M)#FAG7et+OYACdgT@l4c3 z5JG+7sBo{*h@3>ZV!ZY-T=3DS0J$9)#{A6t8nJMYQn4yha9e{(JO#Y8igNyQQ z>FS^0zF2V3Lv{0Vmc-^2-5i))3`tVQ>Gs<^ z)-c!%t^hp??k1RCaoBiN3Dl?SlifiSu;j^x9+<98DR{P?g~%nB6*eDqVfp%Qlq911 z5wJBc3ay>Lrw2g~jg4q&3;@;AIOxli$crL(G?V$&mxdKE*@+CeJ~(_$K zfA4yC%*eWwxon>n3RY5j5GSwH-)Rba z-)J8zzpyQD#T)Yz2Xdkn2eH3ss%<#R5v?lapY%AybGvg#{JGL10M3x` zHuYDle>sNuvmzJ#wYuqOcD5ANg@{#z{~rv>acK$vheIfaA}STsgjV%FG@M!u8y$}= zT;PBhVZB?hn>JSD$))W~?iidr7aW_=bM?em+Q=?GgR0coRzh3H7Li_#F&w;~%Ycis z(?hcd%GpujCf%m|8&j!3oz=6JSi~*wF!n?+*q3*eqliQNRPx}K7TkNFfa6j zwSslWl|sL%ggUzZL{uODJR0)Zlzu<+3=1fb`sl}_e|YU;AtOy6uNAC8wR%KWN17mp z4>gSwCds%F+`mXsd@EKW1^3&P)$2z_c8UlYstx=Q>4WV@ACJ3?p=3dQfgoUhXDBt6 zn!bngj@>5;bGKW1Sr}p25^dT--knK%u@Iw2$p9p~HI^LmMJr&6)`AM=P%;Z)ySB-j z<*DGyob{9LJ0ZGFzB$q&r4vwRO^*)Vr(vh*x@Gt|fl$bxgzORGRT9Tz5{V=a^P#`{adqfVL~;_HHR}HzfHC4}+k>anC+?So3V(rd zZ|)ygSeeqYJz%8L`nDi5$E+u@u!6LO_(b$=6g0vLBqA$LEZ&;kfjVe`MKP|BM6@ib z5I?0E&m2bnAMrT}W0X>K5%3pcBr-+v(Xo1g!A`60fS8`90YB|3F5!fVZf;=$_BDdg z3lSU-&YU`tp?p$$4_i>PV%;ErJ*;{1!@bv?I^!nUd{BC{xrjax5{Qdc`FKDUt47i(;ex+GNULNSo6vv5DxZ;cI?1<0OF+ei;(qS+A zw!OLJ?A9m(v>B`HGZmqPj-tM6ymdU8 z&86CN)mvJhvq^h=zzL|En)RfBWA}{cOw2H&n~~G&3_pU1-kP50D4%iTFw0ZGI9rzd zv(t>2-V-FKb<;d366ZvHrC-|xLxJ8Ah?!h-SK&g7R%PLbl0GtG?jq z(eH7r2!F}~g7kB@T&eeHhsEx$OmMFI0pV}Xy*5$tYay1cE6e(1#8$4X!KCw;6i z&ophRs41yQ8@XR@q^8g$c((M*A}dVq$3mPX+7B0 zfz@=_mdKu?`^yJ_w7dn_24XuC9W{8EZ`#=Qq2M^T3a>tUWoPRk0H#S(S0hR z^NhZy5!?2To277Oev z^^Qn9J{sZfh1DbuE{y3K*mPKBJX7;-vSi^EUKL?WnmJRFRHo;ZhDBn}1eKVEom(W6 zJFo$gvB}zd-LX)%gbmc2L_?%fOxr^4R_m2YWDmDz(g4rpha_gm45)(WSc}kxNRXD( zY!k{Ec};2Fe(LOcCrAvn)A!eqz~4sWJOF1aYvm+_J&nA&Qw%OW+!XkIjqujGY1m!^dPAP2$*5F$c^{y3o}DYpnu;o$vR5DP+vmXgJGy;TdwW3z&B5`d`oth(vP+M7#!^ z9wMBxT~dSWEc}7*&w)6mJ#GK(@QP3rL*tEIb>_Ye^;a&IPS-X>8P=Pfvf`JEjv8=ivB4=4OZk^-;^qBJ z>2I{S({04N31fiDg<2n8K+^Dq6QX0(!9~q+sQ!K#n+~tNWqqT9!~7|)8+}}O4w+9B zeG>9mJYRwoY44uz$?$YVnVwpKK!*|}EjmDZ15k`gGT{fra=;z2bSyU-Yjpjcp1glJ zRS%0ejPUAs#+t{xV}6EOe8|8vGRodV*5f7e-1cC7lW?0t=pY_f5H)e%8iA%(9C#M> zmkO>T74&8wJQ~t7x96aLo3@CBJF19S^Pk=#yDdWijR7EBAV>V3F~7^02y5t}EC7bh z`P!Yz@DMbTe9dlyhg1_pJW(86#lVr z&o1J%Vst@aw8U2*T83c1Z0~i5r7m?8=-a9HdH}Gde$w<%BTG<0WLl8PY ziO7Z7Enrm9XYBj|!Bj6K%m41CLuxm{xzRja%FBf1a)D^3M%`%>E%Z*Hz1ube9Gh}s z)qG2PiAWYvK-O*%zdq-TWfx>Gl_307#wEclOTJbFWYTn_pPvWi(At6#S0HTKkMNki zy!XIq$nz>P@k@YRwG=_xF!iTLUuwEB{(A`5R*_=7XYkTRkORYdt$AW8UEsC*K64KC z>kqcBKRW^}FUVPYJ}(w^V! z8ZE}X+?JmY+_j@1AE|DV9@}qySAMoGhc_)WH7S)W2 zMc&_Y*))BzTwu_lm?&-98t6c$uayOziTv27pO~4!ZPnU$kWJ!c^?}?bKV9x zFNZFQJXCQ|F^!@cQ8bc_@$KUU0lnZ$8T71I#c4Xro!o#-+)r(2<#LC#j}9jLzJyXb z%!}uR#K`?{XgFvajStA5evypIQBu=ncA=gCQ}n(_Iz&9jt@c1!W0wcr!060`DbAS8 z_7_VfA`1_}zzPm+)P{E%!ARduYn?sw2Kv{c$wb^MAh#Gm)`dW>8uXSN))7$BXhF4! zkv-7r(PW!-K2)H2j)K;)cONX@BQS};vk0r8ZZ>@Pss;2asI5C8D%-ddgR;i2fk4*j zU!#0MYK&sRhUf4EvzDtU%iFJz>m(k1hT$-;S1sA>rCLWZ^dSnasYSRjZQ1+J7qugh z^ahj3^y6-BbLewPtd}%>g4W}y4%<>5lA`#`Aw+vaJCPt?vR8wuTJ7z2=o5VodO3B^c9z2ZSQ^QF3H`5r!s22z zCcw~S0Lfxjg+9iLMos_n_&^me-$6L0I6Sc(86$N(PXN_mjC8qa88dekpQu2%72sgL zmROR4j%0t&jD)=lPSUFvz9Hzv{c7-oM$T**8+3k`_6XHpXw@P?)&J*Fl$;>5-ebP+ zhB-*hrzsGMG*TO*QZ1~|_$Nc*$vTO68^t$bbc@BMFqfbkAW@KFZK&$NA1dM3l%S%9?=gn4l*`d6vV9ov5t3k$8SIh_$ z*MKQ3+%gc;hJ&0ThATIVDWlO+)958kH<&+e#vbC2X%qf4RK(4H^5C5uPTrj&{VyiD zM48pBYR1rhF5@qb(Bc|a_P@Lpf>k(6h*kD(Q;?;oe1o-L<^e-!V%d@4s$FxNJnunz;uT^Pz(d`lSwF62 zcrA&+Oj5%HY#Ii(MBlTS)g(g33RU8~!>@tKhJ1b-s#r;>kdNRm{C*Z^;Ov$X^ za;Yj+rhIyo`{&Nam(CL{I9gZF&yL+ap9-&QONeE&KT>S=`j9;j{GuXg8;!0}388Ib zZ5+_dAt)Vxud%1P94x(zYKDgkfjC$=9Wbxspf5C+JZlFvw6E;4gFJsuuTi8&v>@SY zj@z?s*ne1P^TbtK{_g+`O#IcYnnp65?X(ob_~T{l*I=>|hhj0t#!Hys((Wphp!&3( zbZ`s`TPMHq(oJ*WUK3F%DVwgWCWM8A^;JnF=@E#Q4##k)(8jQ~(j}b_w2g*z|A#QU zWS?I+_kK0P^u%*v@Gnj&Mh^bnR%|VTIuok9rnpoK?+T>T0B-p1mEd#=r1yHJ23V)B z@UzaU6KPM>jkim20syjz?#A@{1F8j!s`;gQP*-B2R@hL@`I+885|u}IeHf)WlX-r* zatfK`T8SJHsPp|P(Wl#-b5}1j2`7n99x&qMv7*WeA1T)*npM#KdyyWl@DF2cM*kIJg5Pz#1h#<@X*OEgf{iDwFaJJi3JcLd=8F_|Q3(R+gZ z4uOoVNuS1&m@sxsK)2*bGT*R9Oz zx=n&dxU4$ttFW-GbB?3a@nib$`*>Ekqc!LfmkQKd5@i?xFv{CkLeBzaVH>zkuOTjv z(t|L+zc!e1G(61GAcxlV9{=?~V8<8=q^S^m=U`oDm1SMDT^CYp zDf~k)w+MbDw;6zz%>2UZh3HEMBACsS^bU*_xT)zk3J`8-v>Ie6lra5Mni|uV#@`s> z)*=Tpixr>b3c?4c{nc5TEQ-_p%zFoAg|7Qt&6J+F#bM=huFf@>gr+Ev-qehD zlzs7?5X@E@hpw^G4d@V@08eS|vciYAYUeYxrIDO2p6I45wqsLn7nPnZ4oA}67{wOM z)lpG0j%=;UGv)qj#|%lvEe$HdBq8ydvqt1axqPtZR$$^St<7%BNt2X&Ef#ZPnhVS+ z7QoodgTyqIs#!CuxQno(&fwl^DUw|~a*v0;`ln`}#d#j#n+3i}#8E4CEdRT%nB$mI zs|zF57oxyS%RYm-@S2q^H3Q2FQ?#3!U;d1B)Y>>cT91Wea^pxuEtYj?NA-5I2yFj|bt2HLcZ@=Hs)cml= zxZ5>~U{LUOMvbNgR|U~t)zdT#=RJVH8AzUC%WVNY{TWFA|E3}M8Jf_9q-fP2-o#U3`z9FwsK?gxw4VR{l5F;^^h z`Lv8^qeT@OahbKwG(C(XNc+@Eg%HUk9$liflsFxav_QxrnTAUOJBZg5p2xpB_&@TH z`OMR>h3-T(W_Bm3q6A=Bnq!CCW#m|LujcDFlrfT*sFtbMvE<#ntom>EiZrDV*2C^&`?6a~PC#4#w7q)(%I;^!x)))>JmE zK5`BJWElW)9@NYsrf8EPU4{%M>=FR720R(w44Kafu#}f6+(qa81_b#q9cfi&BtlWD zjpb2!gE8{-e#nM*#$Gk&NTNkdkM9OGqN(@f3Z<$8O`KB{yO1s8gkgrru#TsmN(YYF zTQe*>@zO8+o;v;f7jfD?JhLM{ z@o#<07C^TNtyLgw#+w0RZa9Rl6Sf?GCZg7I9cnI}z^CGU=*RH21(QPWqE-i6cH0X=Mw-YnR{c2d1z(c z{+;Wdi+-6h3C?XZRG=66i6nf^Vkq9Li43xBlt|J&@z>?@g|9@a=A`#I!&k5~ZN6rm zc$(0^TQD;`xAJ7eR#<5Z{*n${o_6sT+CHb0Hb@_NK)h*}93K|k6MlmbqV*HsS76&o zV$pLj@Y=A*2NT(d?ndr1r*$1tIF3|zD`wiEP7?b)AvRi!bhPnnr)r@Slmrfoyx$>b zxcZBa-rwk}2$PC7lrQH`UgMlp;5sHB&Bz=CMJC)!fzpS*dDqj9ILzr7d6PV=-w^^( z2R6cUCx8jXe>$aJnY#xvY$V*ukza^aI={gS4KTwj{+G?sqjK5qEFhh#v}9`=dw{y#P2|sKk)JR0 zmHaH&{GgngWe2C**>i!OjrTW9C<7>n_!BO%zVm$Wg`!UX>*Ye_S_&Ew>~W>*J^>#b z?^^CjACWshx~OZu0OpVh&fqJiQ%QNC9`v57>-42;;|F}7F#qL|x*VpTc0{FLrh(=U zWZBT#We%;ME_8wo2Eb~OYSSZO+)hf-*wLrSU>M6;9yWf!4X97s0%y+fyMHqrg0mTr z2i1T_V8L^FyUQY_uIJgomn;B1K*GP?{&?(ezm8RW03YVIAEGn2*%q(@eJcrS!k;yEDMDr~8;eD3gu%yjdfY%JPt6a{z&>wYXn`Ps~bO-WC)5 z+Y!XxBsZQ*%lD_NQ zN%?fe4v4CAk7}hJNu@1$eLCj%&V|*yx0UOloydWmUgJ5ZB4qinS!#WW=cAkTZRIY)G%^{#7MEw zP334nyGPxWD-hsrJC1_O&%=d7SgaOW9LmQvJ%tksc*@mJGHhr6!3@OvDlZV2bAEQD zC^v!RIlfFlsNf7|Co{05R+C~Ed;b;)9KXt}^=QfcRT0xr77C9Hw_Ux<5;d;IGr`$K zfpa~Yr=$xQka+LV6(gNm_ISDn5zd|)Nv6}vBl(2$FgAz;-4vgg^<#IanTc z%iynPSd93x1fLiKcQh^2JMdEy;QEy=6VkKxt*(!S$bAZdfl(6#qu6gy{LksTdwxK> z%cW)5gQ31Ke89Exa{O^qD%?!i=@kX&&NC`610soABGj7r5R3*mHgS-z0J8+_jDb6~ zj2ZFDm#c+)7z2LCmA{mwMA%V2$%3LbPJ0K^qb624$!Xf2!b!-y_T$r%x>2InYu7I- zT0MJbA9J+%Z}Azk?Z3;6MLM>h`#8+$+)2NMNtl|wkvS<#MPF(4DfRIDC_5_vgCC9b ztQnrGWH?tm(fiYVyspv`Y2wwz-=igAUvlFRaHuotW6!LHFNK8tNAe|EKPG0GYXppSrDqLfxKu|A`SuAVlY*Tx9%N7`}TZT6Mr7y zEVeC=@bSE&UYK$Y;}fClZwfj{(b~Deo7r6Vc1aXWI0Bi$MZt;FQ+V%>u?5o-%QLjN zC8dr@nKE!%+cUzUqu`i)|6ME+&E<4?5^_aNUgq{TOI)l5*-j%@n+={_xf9q1^kV2C zTA)VmMbx4s|8;uiZdG>knW@{5pzD>@jtrZw{WiuWpjZ>s@z@mHTTX%ReTohrk-Z3j z&SW-sGNc){fT<}|OZT(%B%yCpEi;#Io#~%*1vL9DX2<#ogYv{=m-x7iPV>8eQVS`` z#nT#q3!BsZg8%Tv$tS$@$1vLMs8qkh=Id}FZp5>UF^>y35u#Eq!s0z*f`X1ydExfV zMnZ)L0mS84b)pYtr>B_yEwZPIHuxm4`wZX0<` zwOYnZqDx!lE8Kb>+qdl&r-EpBeo-^Y^EE3-EfM!<1vdS4<=_xJw%)vjyB=Va&RM)|T=N^1>dc6|lqSMu+@U$~ z!B|C!$W6CklZIQFnFUiqRF04faLhO66^Nifti~~GFI1Mvi>upgj25jwDb$M}4Z6ug zZo#w-+<^6Y)8n9%WJ@CCwIJ(-YcA@R8-gn91t>Yd)o7Mv5ui;UNOaB;m%geeK(0)Pzkn8>=}$ zR61pv0HAU_I|fkaK)|gpVYD{xtQc~R{YmOk8pd4}^wirVHIET<7CNM8C;B_OL3Ya2 zSY^;INXvb11ovkIZB)mF%I_=3`Y}b-!0O-CAQFWS4JqEQMX=4W{$RL8ID!`cbG8K0 zacY=EIf6Gj0&OqZ^!Bw$j3;FT^~-0E1PX=deUvhceI_!f=1hMF!-C`%gPi4eMp{Vk zPIr}h&3R6yUrA`$vC9e2-MJ){>+`0 zdgDzmLa)9soYUSG1P5v{I~33eW9wGfxqWj?^Z+=x2T->43*iTgSYrSjVeF1Bx0M@hBhzNRK) zc+{!^dZ&+@Ih&w2Cq4j7ogbx+WkI?(Ec1U}11I8~FBi>HkOz?T=5@lCN~l>@gL4cp zOCz*@ihCn-pokqQkZA1sht}BSdV$|g>z-wt`LktqT>VU9xnlQwPf-%9S?g zpQW3(X9a^K_h*}&susSL->-0@$;)VyEwkRj4|K)4BpREM+z6lY8j8YnhFAG!V9U)t zSy{lQZIHz)E=z5FG=<#{7ZG>!Hn#Z!o~FwN*O(Yh3W;e;xiny^Jv6{Gl&Xm3F9^Hq zPFxW+K|^fkbmrLO^G+?qVC*krl&V9oeeRj*b1(j4gL=$dM-A8CBd>=Uo=ss(;MAB& z!T;rkrB&%TK{vid9W5Yc`}?Z09oPDkkc*nP>wK+E4)5Tf>pDUW#4o1{Z)K1QQQ%7l zDK9}&EEG?X<0FmfK#uX`>^ETzbK%@Q_}V)yZfW$uM;9jvu@N$HE| zzNFtQ6GHP@nZ5Nu;Cu{4@m`k4m(B=+0 z3Bu8q+Nt-F1LYir8TFmESt0Cfd zpzlB>RTCi@3_q^$g%my6WbrFBU`A^}B>Lbqn3fzd8!8%6cT8R?gk7j}`ChF}Z0|Uw z^{IG{#1+4Y&;U%k*R4==Q`%+-8k7(p!A>?WSzg+~szP=~crOlttn+B_PE3>2#OO}L zC0~7?=)(jrETKALdO7hA26f@&<@GqDVqe4w6IcdLm;f@ia_SOA0O3( zk`+bn92F|aZn|!d1 zjmSfsdpoO5tPKi&d9d~gTv8J;pD{B@0ub0T#dCoL15`)0Ycg~o{finHdiM?me~3fj ztn#7i15W2tJdA@_XllrS4&UgO7ZSSIcw~efSIb$7mZyoq#}*a|f(8Fph=yK8p}d;w z#cBjsbd{f6?|w`oj}7ZgS?8yZIISy>*}4bh z9XTNnEyBBupPw)r@x_V}SpVC-^foOdGFWb1i5r4XYt@91n>YRQcSU)re-LR?HSpqC z!=5dzmX@xOkQ@Fbsdh)@F!Qg67;=?LzPUm%lQpcT?qsExwp4lS2M1G*lEk?Le3Yvw2@lN|9W#azMMJZ!fqu zutEs~f0F+*#%8}mS_&?C9_LJ7+G-l5qQF%3@dy1@y&I7mC)^P7F}oc~nMuya`DH;; zT#?19$G-By{kIHEFBp6YI`1APf7O$mwGxysjK>Q{IO|Iy=&%s>0pTS=ZX=p)I;Qr! z%`t@ol7kng{eGJdX}ZP#?_n~684l6~wwW?=9c@xGrCw)Wj1P&cN;3uB&);GET#c%T z{ptfrvazM2ZjpjgbE-dqd;VHt;Z^?M9j(}dwvOK|Xsh^Fn>~*(YF^|qJn2<1Q+a+I3d5%!P?jR%`qyl1OY_y|c}e_&?KD`J6_=QVD-C=W7|?w1D;${p zKW1zCiX*fGJBwuQwYA6CUA8w7vAp&8Cqx z8GKiw=*wYNHwo(yAui9#$VY~2P)f^lj;K^Vesm%bN&6t6YMpG6KJ; zy?Q4iTb}ETSHCW3e2!dFNz-VTJg3ptt`6>34OfcK=c=MkHisG>fr!n+}}Ylcv|{-<{E(^oWGwEg%v{P z>n;w@$4x$dq(B^;oMFZCvm5LKcR@6?)#L6AJk`Q$ey32cEjaLD=c{RpvyGHNw3J2UHpMp|=eFT{#h%l~HqGIb}jwffu*8t(xFQ;8Vof%rb>8 z&yt3v(IiEJ?ZlATBW9=SBNrRywBjjJ&N~!iCzN#tasyIuR#g+(B`p`ib<0vXKu$+N zl1YVaTH&_ESlSyNt~E|5U7$xKTkH6cz8$GL*r@z&yUQI49@6ZHVTbDz26%Y`A0IDi z-|tRRfBA=IqB-u^z1utmr{Ld1B|KX=jGxb2Ek`l{Ep7(rtIAlTnJ%w22wD?9BHD|@ zNJwK^VMTJv&n)ZV!R*{t4&)L;{!`6qYAkJ5$7q3s_qG7rM?-(ojd;6B6B~l86IQ!7 zx^vm4=qjxZ^0T}0R6<8^U~9&0>7M#rD`dEWBc>RvB&xMzdL+Kq69GD%cm6!3mpz25 zmD-M~=$FdIu$BoJq(F4!Zi0l$htXE?mW%~A_IwrML(EGy4G!i?d`u?fRFabPG{no!>RPG_N{r}B8)c;Pd~eWg2^ z-urgga#ATG18Me#Fk0v2v3e00$P_~xR|Ic*O;yj^GuRci`Yy>$CVmPtaqVRK)wVu^ z&R;2sm~tWWgz_-yNK%p6QlAd0Y%!nVf)Vp#gov&#u7P*z#fzC|V%?XwY>q}QmE+=^ z_HUnjt{dzX^^cmhS*-02_9hZ$K+=gcewdg0fi_g}c$i?Ed@&(-(CYAV^@5L=H@6yY5{mwxRugFaZ?My4kR zPWS~*^DAxNP$LD&q66D}Gy_!|j72^6>iLWqSt~Z3)MKGk_m$PvgJ-7J`aujpL0ZfV zakFMq`+>*`O?nA(F#AZM^3ZsyfY54rE4le4vtHn=d5wp*l{DaxOSP?~B z&5t#$9XPwQUvndiQSOuBX$&QhcGj(bbC{O#&W-&R^nLc!?ikU44CSZI?bK{6k{iWr z$7H8-L-uc*6?|GK#CU zwh}6co8O5kkVM+~I-e_A?~9!y#2SYG6Y015RZsy_Hrqe^Gs;#sI6XfVIXFUd=^oOd8`8B(&_t^Dol8NT6I{5O! zdb(9@+w@KmHmWEFqKZljZLk1xB!#(=B>e9sFM8VkfheB=THKnJJ0RmF_yT1e)oJ_K zN*H`Logs_mz}3~FjJR6}ilkLmd_XrNJPA`tM&Xu}>i$PKZhcRdRIa`GC9-vLAazuD zz#2Io(fy&U-5t?lSWmhW4d2c*;aiZ0(7)Nao}oJyGae400(UA00HNy&98}+Fi@LJf z5^|pu8(hr%a|&N1#A<_Cxg`?A}3!imiG<(_3#(q;yePP|eII$@g|*+HC`i`pAv=32|CK?k}1mboz3t#kJ?G5C`>a?PWiik)SDCX^j7f?2 zx7s0(BI8k*T@>ITKRf*arL_r5NInKDiepGkG(i%yeKWnC?DXXwnA$@ydlN$8J@J`ff^ z%-vJ_)F|-5BHEF`SvFLyqdw$5c>r}PPaJL~I6Xh@Ep`U^*wK{|JqmC{)=4Tv{@+i-pOy_y5)Cb|+{!CIo`! z+Wdt9+03&}G*VbF&pzm~`2G-J=gEQz+Qc?wfee@eKyhxoW;TFixphgPr1|y}O_s1` z42TuBTGDB zRqZ$Oiy01tpQiD9a-sHWz|sbCbIvSZ$!6kbE}P2|;4oETDf79_`~EAqxC|6=@T|ut zkunCvTy;y^VeI{)IID@Y>($E%%%V*&fghyQB=DU7JumJwJ~ys+_=AzU5Zw7L{=maU z7aeWug+YWTccEp2!6ZFR&vuChVRMrl@2oRD=#fOjtlH9`-n~E0Cw08}_Sm0lSou{V zBQW2xS2bb`j!QDC1JEHvv#(=dwdfl6nVzWwx`w(=PVEzgaaeCF=5jWYJ(_(yMzQie zkiGd6uAJr_$0p$zW_lB6fnIa~-c3Pt*#v&VB785&eZ_1K@}NIZm*CL2rK3}ybR5px zY*O}zluS1CeLuy04|OOd-1@J+OGQv^w@@q!fLQWua4t|jG_|Hn3$j4nn;L6_`&7Hc zuzS6<$rYzYe2FT28s^oSPXB^cE=Truk|F^g1r#uZc$iV+n=IO;hngXjH=(Ak-*8>y zitzRYhQg-?B*7eWdc>cE2$2aOmPv?9a3B*XJ6D{5+W-gRx!_|WmuKpkUcViLt0QU} zLW@AlKQ0a*EApVa64D(d@CtS|T;^!@xS#^Wb6@a0gAtvc1~?0~?U$x$r?5B- zOybaDpV9@p;_!gu27z8i37HHD6hpe=0)kV+8zn=_P>-2=&1FdVMFX2*76(Dpcf~W9 zrOdY9h4A z6!chH&u2a(01v*Kr>U_rxdnb%#NXwsux_&fD$nCDkn7bEX_y9iDp!In#h%*(=oN!t zOfqs|p?fU7+KIb+27)i66~}frLwIXoA%xLWzx;{;knUCj8=)moGsf!)tsD7}WbnZn zLpSHHC%BrW;(V=Xah8j7WY7MvHLU!ig`7k0i!AEeYmb*mh(fS>xfFL-5)!3)h_2zO z8z_@iWYQzaSX`6m7yad+D>NXZSm`}Ujee;OEJ`mivu#ALDw#KHabxT-4CCg5T%p6>u=&10_h;G(Z0O~F9HIow4NPb`e-EY)Um1!`I%-2 z8hmD;FT^SVZw}DOB4i!DwI#td<&#W&XpQ$Z*Cq04r0=Ezu!a*5x;5-e15 zMqd`+nvEF$a0$<{n|?^%?>R!eh;m}UH6@Q~WIz@j8K;Sv$RVAE-g(_IH*rS@(V&2$ zQNgJe3922SJZB+@qnkpKA%NN9TT7#my(;x7S2(()>?!MySnuK%)Ix9)le)!><%&?r zVx1Z;$|<^OPD>GyL5JJk+^-6_Z8Q3mc07R0CbDwYmnO& z-vuoka~j6o?08m_>yD;(p?beWv{4<^iO}YFPwE2$0DT;|fxiIi`3!Oj{pS^NT|v?4 zGSJq6NACIer2&~8&2vvEYBXkQoHLGBL{?0~*BV=2j{0V(aVsuG@$_Z>$Vk&dJBMV! zL-c|Gg^;BeF6WnAOc6LdA`KZzGBOb3;W7_Z{etLwdXxc%<;|cbbCI%$M4kwm>o@p0 z6Kq57rZiYnQ-{-xTEEm2ZmTacwRmOYN4-1B^OsBW9Gl8Rq*+wQ)q)vhZz|Vo8QQ%% zT{p7#(EVMla!a2sCc_NAG->G9%7$GD8b9g^tDJ>H|6m<$rBvRSxP>FvAEGlN!&8&8 zc?l-<@Y%?17~00vQrz52=ie}ST3HRcrnEuVO_5Plc{OxRKTr;yA#%}+dsxD0*A2&i z9|~^d^&=x-zj902p;I?Tc0EctJs974rT!s-k(mD@QdYm&|8}^&OqS6uu?@s*jvFMI z8Ttl3sbhe1aL}!D(_&1hzQKZMaa{4E!9J%0yDeuQ_lMoCnbJlv7ib&<;!3Yd5WOgr*ai6>FYq*|1+b#7R( zv|ntag1a`x1mMfx`FXuJ2s}pfx#z^}pWZ7+IlQ{>Ng$1`>n`!!phZx%ysmcRJ@`~* z_^cV)#&h5@vW~CO?zzGY=%`u8%tXkKY!^!`a6+X49*`}W5yTGe*@{fm?f-;`n4x`S zzVqGQZbQ62?75}MEk$H2!+A-BYl~*hM4(sbON>!GmE{4ds7lwH@Pyw_BM|9H`+4Rta$} z_~C#sgOylS&$*C8?anK$Cyi#dtxb!Pr#BV3TtDESs*(+WAg313YPfvt^s%TsV8obQPYz-c+V~iPVanIDhL1%l3kG560XPTn z-7f|A%NkC(y;v10swJrVK!2jCNA$riG zOvXL7>{*bc2hnKT4Xb)*3@^%m`|Dm z$ScfVMR=Ux@>1QbC&?iDAK576b%f=NYz+b^9AgYe#iB;6L6+Ye7J7FSqrF%S>?!?y zKlXEkL#c(_3(O1kU-puqIZ69^<^|cR4Ix`WP;iD|S4+q|VWvj!EOA3WAI8-j;mfDy z0(F7G;JQ#jwHG7fsYV^AIw(gt2YDRzTCPxu3M6^&Nv4kKPQLcViAsB$0|&UyuADfM zseRx*$xqve!f+XbBQQSmgdlVs)J?*^dYAs$k$tZ$Gl*Nf*sn!_sEz{bXI~~=Ra5^S zDC){=`M0bCp_UI|_vd!tW3%iCwq7n3*4V*hThKDYb-V+uKPc25vyF0zukUX(E5UU2 z?H3Zdc%Dvh8uDocBe&ZFFzw!%>aXD@L&2!L7Bci1^>4qQbu z_)iW7oKY21%Yu62xp;5QvZejp+f}(`imXlQ#-8&X??A10n^LG%2qmc3#YuFRM5Xk7 zOx7^G=fuU+$*$+}9^kAohuY*vodSt}Hn=`pd_X*!n@HJauWig&L)TU}J+Xxd^__QT z2IzN~!?>FxnFLaXUhU=~v&aR}cS!P97?kj{-{5Ota}aR_*61*NR~lYQ-YpX4bXGm1 z0{P_6#2xsql z`r6ce-J5c&D^u;(72`3)ZVh%D|N4mOnbkm}=BZxe8QrjtmxgGjO=5cJ-&lHr$%8dJXSFc_%JFZf?N8s##2yd~GE@HFIeitDny4GF~(kXq6v@SfHX-6B> zw-bOQ{g3=eH`gPbP?wbZ4DrlT1Q8NtZV8i6CkKD168}{NT-q>x41AE=J_{3KAaftc z1g{dnq6e$5-ovC5DXNc7C~j5+U39F63QD4g+5VUv)#?~KtddG%3zpP1E}0{cc5r09 zTjSqrI%*P!1;4_Wp+=K=cUghs{>W%1;9VVsUv4j}+WpCE7Q2W=A#_UndL}VeM2W$A z^_Nvg&MjVmmdr`H7J4vURR`;%q8Q7w_ofK`b-a`R%yDXCKv^Xksd=D1MP)AjS>UbUQ4*@iS z>%`Px)}n`gE78Z+M$MPuo}`MK$16wBc(59*W&*NUY=jN5{tXLoFdYktwP}| zE^WT|oS#c0_{4|a@K%6BJfQFFUXlsFl8-rOdGOX2o-uM)fj-RxaN1BfD8J1iYJuP~ z3D%0l?nF}fYKg4@t@VcY;=vu_t#_O+1fC~Asq7%zXG#Kzx=MqiT8;+HXlmx`XR!o` zAY{$73M4fzI{?d7I&6?}1@>flKU_omYu8{=AS*Hv=lU?3Q>lHDG96ttOZxGYMg%BS zVDto*q}r+L#B0!?^f7E6IY$moFKhz@L+)o;17r3v(pbS68^ofpE{E{*&@3QZn}e)# z>WN1kl~b|I>SOr*d2+y|JD7D8DxQ4}x8xu(v@8%JPFm!SVI|Mk5Btd?Ulli#0$e3( zA6kM`9;Q_ZN``eake&*Bn@)~D7m6B#!a z@f{c4e8CzxJw=Q$>O^{i^zM}HqM@XPc3S;rHT#L=!Kb~mVDJFY0j^zC28t;@W=@K^ zx(!3sh#zc=Ofo}}hx%Z|RRKzieHln7X+Yc*UX`Lx-J$QS=dzmw1CbJ)Lv z-TZ(#C59o|+UBPf-1#$1ewgI*FfhzPu5w3mhvXD}iYei2{bXO^}$Wp>UtA5_uQfDfI9p@Ui7gpnhRH zCzU3q`M>q-z42rSpgD79fjUn&9=@tPV73jOLK!7R(c?TEm1kBXI{2xQ5paH-f5>+3 zLI{i}S!UV5PZ|RR(N4}8XH1rRwe44*h=JM^XKa26f|(uXR2B41fOh{VSq_oF)Op$w zG?}V1Bz}`39P!GvCRwkk*cb)$*g`30HYk&vu2L(oGG(as!e}aEFTS{fSJ>%m`!ki{ z+F7<*_ue50(g}N)ch}*jvCi3o5MQfX_IY0le)c^Vga65p%I&813+k? zMl0<*$+?jO2R^3KeCJw9#{j9R;+1ne1W%u>$*L9%o?i&9z89y23eZ(YR>Rb6aeE=g zx)BS8wLEaZXnybRQJf+cpVio5>q?&kFiT`KL|7$p;}R`p3&Z9H*_3TR>G8Npk6^!* z1@2Dr_<#>c{?lOZMk(Zzsf9zU856OsL;@8MHP^OB?qm|m@^*!+naMQbykXQZvoawE z6#pn-=UI8PRl;C;dURep!YMWN`*5W)BfyMkeEIfy@(cC+oA^L0`E8mQ=G&K2?EGNmZFV}8C zlsxV#O_u4geTm#%6r23Aj#qrJN%MJf=F94qp|5v-@sPQ=|MO%`MFFU*` zih}ka_a1=-Nf`CUCl&utRRJ(hsv}*;>oCAj@(l8qZ%@{SWT$!Hh{U%MO;Sg>=#)8a zZwaR=ASMyuTaITNu&O-KyX*@ZQ+WW&p)pE!VbJD!Ma}xb9DtmKD?>N^<}{Sh?1HpEOb zGav;qC>!McSq~gGg;0FJA7WgOGCE~5RWs_~up-_d#YeBSr|-T}f1ds(l(sjciC?P` znSF?dDWSFyuS)JQ`4Ar!Y}TTBp;y*8*t?VeCJhA2rW~g2Xs&6+_L{Yy|IRU>rkYcx zE!QR!3+RnaBJ5tb_MI6&yh2;8p{H|ShShm062jV_Moa`+=0_;E@)Q7C&?b!{<_lV? zMhk-d0H-I`9l$bc?(23iuYz6|zkzs#O!UQ_IGiJD}>h1U1f zu>MLhKkbnEe9Rxez8wb-9c;;QaQezs+!XnC#goA`MOoqIliitEOBF2dQ1+|1iS%YB z|HXZj=rTyh-o{3jArCGuT^U^Q3LFBfaouyAC}Z*Y6*a4!1t>Nzd_?Wrr(3>oYFTnq z6~9a2pNFC;A|@!i)Rz8ENN-|k+w2-mi*ELLY0{xgC=_#e@X=z-2aN=x+OTWsKda}-C+(R}s>MVaG z{nBkHWfUaOXfw3dp5 z*9f;GUGfXU!rIkujo7lwx9x5jnx<8VEH$-wSU6>_j*w?*6l|nGK4oOVpu<@44nsTo z(qZsr8}jlfUU$77>(8pLfhjXhE|!|y@{9ciO=XzFFpJJW={xtobz^t=1#qsXiX^p% zc3HH3V&^6xqsL4xrk$w>ufg7S#b1EaO17ObD;>_N-U~GG1ut4?{~VZE>w*|vZL>V} z)&s=(AH$m4DtQtgyyff6SV_zE-dO0AnGdb(9JJ%6-J_@aEN5eRNjAMftv_A`xLaEY zhkIiX+kH6t5r}1Wyo8nb-VLGeVC=yqq*&J-Kzrv$7O}89qf}8iQOc*=^TE!o|FbJp zuO`mAk~$rQ9Z-PzVHUEf`nf z2E1#wu~rrDWGEEPluNI0th;IGVPSMKxASB*ZS8hJKfb)#x?BdvGYon~OndaqJL$aP z*yS)n+-&7Bl}j!sbO~6LH0*HzQr-XWUZy$xJwz%9_-FrTrZ5gJnL-l%^XlctSmABWzZ)dtx!x#}OsLgDH$Z;-#VNQW-> zN?w|%zCSMzjPlfFbHXBmqAufBj??!?LFh?9a`v0=dqSC259xR#Mb&!JFZKQz+cX`2cAk z-(%t+GBqK;@riidI;!3}nT_NYGjvz0d%H}q>V!0`al~5)WpHoLB6`4b;A8F6XbBoa z8AT2Rw*H_l)EHW}+zp#ii23bxCJ>h~2jv_b311gnJ(@Qfl6u_eJh>O@T;i*0; zkMCc2*+%(0FQn|p#Q?F6u=jtPPH`A_5%am{T?sR4CAc}Y!f5*fa(gv?IMu?52pe(% zMm7&e50o1Ha-LE^M<}HrZ9#U0n4&X*bC2CKmfCEbW=faz+b?0ZPl_H*?#cdIS(X86 z8zRyyo>@c8&~vAb%}U%^-070tj`qAyb(1~yA>s}i1;>|N4JRO=hq<3_zyfh|YX63- zP2A!r)U-Be{&_b9oK?6h^wsWFzvgjJZKZjMv@nxd$lel7Z<+o;lC63HDm1_Y*@(S- zr3fM3a*IpXiJG`?hlmyWNd;f9T}{jE=noP>I{#tbpq4VH&34%sV6LV6_uw?j0U1b~IUL{Sqg{F^d>OKE^o5P)5sX|2&v7)bAg#NP{+R@R{_RbZ|`#l1?m&vW%xFQuIu-^F0 zgLA=ObOeSVbEELCcF!O>Ck*G|je>@O)Zhygx}WdWXp1yzFua}c!$<|O>xHsLt{3r) z)lG*UYaadOH8b`B99=*cx=7G~_KwwEVK(Q;Eic^Lsvf=D%-ubrZxbE*Vtqpqu@1c6(#xEH(C zKBMV!0L{!Vw{-|I!7OFrEN@;ipd?YU(77Q)IhxegqfWpykb4IVo-3yh0jPCj9xihz zaEW)C!8_N8)zU@1ZrWnE*sA>aeH%tB99WOD8i1Y_YzNv7oD-FJ>x6);{O6^i8&zDdcc;a=gD%;^GeH4`ct~ zfUQe_>APJ}`5hzwRVr50loH%{e!V9~-t4;3X8}pE(M*XIGz@`QOqgM%vrB)g_n&J5 z%g)yaYi|qAS2KkzYm#)TJ~*ca#&zxGO#6ae^S7wd%$0la*cVAvbjv1b6)ySZ!knS) zl*m}yv4R&e{Mh)+z0gWK*41Z-F`p3`&m|{jy1=RK? zlsX>a(Ny_>a4o|o{)oIY`~>B7pL=d)_Dw30$(jhY-q@2kMw@Qe{nz2JL_=q=lOIRa z^;nz*8Tq~bxh;!Q)9PLi5#27M_%~O9Bsnm&xU^B?+1&zTiQbB6wQS5g9io`o7|U_c ziz-@;Ht%9~rT{)N$;9Byv@GxN9qFKjCUg5IM$wrU_vAY{q;VGFeSoNW7RSXDHZB== zL~-e=v{E?)=*B)2NTig_v#LUq@3PjAz8fH=_foWeGA;{iV~wLGD|1;N{@OnKPm5ea z_GMFcUnCkYuqSwn!hJMIzs4z;2qHqCZfo26+ZZZ8M*+^_#LRo>eUda%e=t?Bx< zOxr~@J$8YY3swh^4V9auxGwZgy^`RdLS2%6{^ye?TaAF&2spClWS{IXYGnU&BI659 z#!9{!YlcvDRk`qH8=S4`oM7}n&ejqjZTV-g^7tz|8>7iUh=cMeUbNc4n9|Z`#6Q@g zOV!l?%V@yelW*a3Ho+S9e-q#L^C3WYkdl0Q9l%sQ-bc+sp57n? z2P`Q_v)Q8)#SH+n4(|ND#o@KU(S|I%V-!~A)yEk~J@3`Co)q$7tR0Hmk#NUz5<8yt zdCx?pC44#)sB)-sh%`ae(O$Z~TVFUMoWA0r+a257{9P-~y4@w*^Q2k~SVx2)GbT85 zQjgofWgxZ5tH+r$_{^5$g0 z+r}A+tqO?0Z?ll`f6UohyztsQ7()0i z?zSCt^R9^6KwT>ziB%ah*b4yF9kZRhWkhAjC!^H^>X`eSiX!n~-N(*mbeEwfK#2XI z6W?2yAFe$gz3}6A04WQ1HHbljYZ-@QZvP<`V+Ih`Y&DjAp2-j|oM)xB1$HPP-fv?< zF!j2A$+96rNxQ z0EKGh!|CAyQ06VI8RDa#%1(H}ZGGq=C;}4825JM!aHU~|*UvizO?hX!ea@Vs_>yS* zPDW+m{VacsIY6_TsoksCf7lk8@l6+Cs#n}xQMqVhwWA8*0a*s7`GRS82AK3~HtoXQ zypL6;@woR&(*#S=%@n#LPyDdF$_D+Uf)>DrUbd+#0o4OTDQi6^h2Q#R|9 z$BFU&J2<*#I0Y+=v)KvwsQmON*cqDYPl)ow=)4HG!$fxF)9{*W zYYxn(&*7p%TMyK&56Jk-_YP1pNFEwUOD;`ls2?$u3Y0;v6dEV_!Y?E zpZd$7Ek?z7&~FcFJT23@zCCSaYQCe_=ks$NzKi(8g5 zak&@Ki>Fja(1eGxN#Q@~r07WevU=rdsB58Nkhz4@vmT!ThfN@Il6rhllIb#zTa1zs ze&v%rW6y?hCD9bd`sV{y(5P)+td3?icYY!Mv3P$L?KBzDS$8)38YnZTXVMTd6&y2RQ>x&r?X|wnRj`{X99A6wMlM;lYtSncxMO_bJVz z-#RwAsz@(LAj^zF0<86+GFSKx)30c~;~am4r3gyM%jBoA&VQEF#MvI~Qg84a4;-N5 zRp%KN9zIbV%Mg<48*6`)TxauNiumvO5V-Yx{ERPbz1bahjiMr9y1eY(NOjlyMoNu{ z7EwiAfr6T*&M)#`vPO*Y`c(@Z47@9})Ubh!p*#LlSy+>%uG%n&%ia=(@TWi$ zuI|Dt^cNNo+>+I)9#qm)0$F>LFVkvkri(*_f_}>h&B=rCo^4&5z!6&3b0^Kpz&{)T zEB#W{3cztE9LVPIPWH@3T?sP(X^tK7>1S1?PSpf=^QvqiV&_&SeZT85JGtVT1KX+) zd^$_6nMzho+>m1g(XN}%`P0O!hjlOf0Ce|)V~kcGZoDPTpyo>L`|`6EYj!+5+I!!_ z11LUSXEQ^2+3nOknA~`tNx*CO8TPa2qQ>)oc2QI+<(&6%lsY+wDtBo2;YX+{@-ad4TY^GoRo$Q-5@v4!4kMvtZZV#wC}Zq$$>} zBCL0@ZDVN8K;563kQS_GP-5e$=tbfmz`~i|*5l8NX3lY|4juM9aS$(Z;aA z#A()0aqydGhHeCh?%NRMu#g#&`!N0+P1WExM=}{V8E=v>{AKP2KQFX0)?PoSmkD!`X!D*AUZWVk?}4{l~O+N+p4h#k`nClYpb z^VGzLKlw!fsf$2|AFdsUViZT69Hz0fA$3``3T>N1B~k|L=31+@iPpWDmXy F3_=@tMn(Vt diff --git a/scripts/steam-workshop-query.py b/scripts/steam-workshop-query.py index a044468..fa1dc44 100755 --- a/scripts/steam-workshop-query.py +++ b/scripts/steam-workshop-query.py @@ -15,7 +15,7 @@ Usage: # Output formats --json Output raw JSON data - --ansible Output workshop_items and mod_ids strings for ansible config + --ansible Output the modlist as YAML lists for vars/zomboid_sophie_mods.yml --report Human-readable report (default) Examples: @@ -302,18 +302,21 @@ def output_ansible(data: Dict) -> None: seen_mod_ids.add(mod_id) mod_ids.append(mod_id) - # Format for Build 42 (backslash prefix) - workshop_str = ";".join(workshop_items) - mod_ids_str = ";".join(f"\\{mid}" for mid in mod_ids) - - print("\n# Ansible Configuration for zomboid_mods") - print("# Copy these values to ansible/roles/podman/defaults/main.yml") + # No backslash prefix: Build 42 required one only during its unstable + # period and rejects it on 42.20+. + print("\n# Modlist for ansible/roles/podman/vars/zomboid_sophie_mods.yml") + print("# Replaces the file body wholesale -- keep the header comment.") print("") - print("zomboid_mods:") - print(" workshop_items: >-") - print(f" {workshop_str}") - print(" mod_ids: >-") - print(f" {mod_ids_str}") + print("# Mod IDs (from each package's mod.info) -- the `Mods=` server key.") + print("# ORDER IS SIGNIFICANT: this is the mod load order. Do not sort.") + print("zomboid_sophie_mod_ids:") + for mod_id in mod_ids: + print(f" - {json.dumps(mod_id, ensure_ascii=False)}") + print("") + print("# Numeric Steam Workshop page IDs -- the `WorkshopItems=` server key.") + print("zomboid_sophie_workshop_items:") + for workshop_id in workshop_items: + print(f' - "{workshop_id}"') if data["duplicates"]: print("\n# WARNING: The following Mod IDs had duplicates (kept first occurrence):")