diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index eef65d6..83d0e9d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -47,7 +47,7 @@ body:
attributes:
label: What happened?
description: Describe the bug clearly. What did you see? What did you expect to see?
- placeholder: "A drought event triggered but crop stress never changed, even after several in-game days."
+ placeholder: "A hailstorm event fired but the notification appeared instantly with no warning. The event also lasted 0 seconds — crops were marked damaged but weather never changed visually."
validations:
required: true
@@ -55,12 +55,12 @@ body:
id: steps
attributes:
label: Steps to Reproduce
- description: Exact steps that trigger the bug. If you cannot reproduce it reliably, say so.
+ description: Exact steps that trigger the bug. Note the event type and in-game day if known.
placeholder: |
- 1. Start a new game on Elmcreek
- 2. Wait for a drought event to trigger
- 3. Check field conditions after 3 in-game days
- 4. No change in crop stress visible
+ 1. Start a new game on Elmcreek with RWE active
+ 2. Wait until day 12
+ 3. A hailstorm event fires
+ 4. Notification pops immediately, crops show damage, but weather does not change
validations:
required: true
@@ -73,8 +73,9 @@ body:
If there are errors (lines containing "Error" or "attempt to"), include the full stack trace.
render: text
placeholder: |
- [RWE] RandomWorldEvents initialized
- [RWE] Event triggered: drought (severity=high)
+ [RWE] Initialized. Events loaded: 12
+ [RWE] Event scheduled: HAILSTORM, day=12, severity=HIGH
+ [RWE] Event fired: HAILSTORM, duration=0s
...
validations:
required: true
@@ -83,8 +84,8 @@ body:
id: other_mods
attributes:
label: Other Mods Loaded
- description: List any other mods active in this save.
- placeholder: "FS25_SeasonalCropStress, Courseplay, AutoDrive, ..."
+ description: List any other mods active in this save. You can paste the mod list from the game's mod manager.
+ placeholder: "FS25_SeasonalCropStress, FS25_SoilFertilizer, Courseplay, ..."
validations:
required: true
diff --git a/.github/ISSUE_TEMPLATE/compatibility_report.yml b/.github/ISSUE_TEMPLATE/compatibility_report.yml
index c1dd13b..91f0b98 100644
--- a/.github/ISSUE_TEMPLATE/compatibility_report.yml
+++ b/.github/ISSUE_TEMPLATE/compatibility_report.yml
@@ -12,7 +12,7 @@ body:
- type: input
id: mod_version
attributes:
- label: RandomWorldEvents Version
+ label: Random World Events Version
placeholder: "e.g. 1.0.0.0"
validations:
required: true
@@ -46,6 +46,7 @@ body:
id: other_mod_source
attributes:
label: Where did you get the conflicting mod?
+ description: ModHub, GitHub link, or other source. Helps us check the exact version.
placeholder: "https://github.com/..."
validations:
required: true
@@ -54,8 +55,8 @@ body:
id: description
attributes:
label: What is the conflict?
- description: Describe exactly what goes wrong.
- placeholder: "When FS25_SeasonalCropStress is loaded, random events stop triggering entirely after a drought event fires."
+ description: Describe exactly what goes wrong. Events not triggering? Double effects? Another mod's systems broken by events? Be specific.
+ placeholder: "When FS25_SeasonalCropStress is loaded, a drought event from RWE stacks with SeasonalCropStress drought effects, pushing stress values far beyond the normal maximum."
validations:
required: true
@@ -63,6 +64,12 @@ body:
id: steps
attributes:
label: Steps to Reproduce
+ description: How to trigger the conflict reliably.
+ placeholder: |
+ 1. Load both mods
+ 2. Start a new game in summer
+ 3. Wait for RWE to fire a drought event
+ 4. Crop stress immediately jumps to 200% (beyond the 100% max)
validations:
required: true
@@ -70,8 +77,8 @@ body:
id: isolation
attributes:
label: Isolation Test
- description: Did you confirm the issue disappears when the conflicting mod is removed?
- placeholder: "Yes — removing FS25_SeasonalCropStress makes events trigger normally again."
+ description: Did you confirm the issue disappears when the conflicting mod is removed? This is important — without this step we cannot tell which mod is the source.
+ placeholder: "Yes — removing FS25_SeasonalCropStress makes drought events apply normal stress values."
validations:
required: true
@@ -79,7 +86,7 @@ body:
id: log
attributes:
label: Log Snippet
- description: Paste all `[RWE]` lines from your log.txt, plus any errors in the same session.
+ description: Paste all `[RWE]` lines from your log.txt, plus any errors in the same session. Include the full stack trace if there is one.
render: text
validations:
required: true
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 6f0b241..d0af8b6 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -8,14 +8,14 @@ body:
**Before opening this request:**
- Check the roadmap in the README — your idea may already be planned.
- Check open issues to avoid duplicates.
- - Keep requests scoped and specific. "More events" will be closed. "Add a hailstorm event that damages crops in a radius around the impact zone" is actionable.
+ - Keep requests scoped and specific. "More events" will be closed. "Add a locust swarm event that reduces crop yield on affected fields by 30-70% over 3 in-game days" is actionable.
- type: textarea
id: problem
attributes:
label: What problem does this solve?
description: Describe the situation or frustration this would address. Focus on the problem, not the solution.
- placeholder: "I never know when an event is about to fire, so I can't prepare in time."
+ placeholder: "High-intensity events currently fire with no warning, leaving no time to react. There is no way to distinguish a coming minor event from a catastrophic one until it is already happening."
validations:
required: true
@@ -23,8 +23,8 @@ body:
id: proposal
attributes:
label: Proposed Solution
- description: Describe what you want to happen. Be specific.
- placeholder: "Add a warning notification 1 in-game hour before an event triggers, so the player has time to react."
+ description: Describe what you want to happen. Be specific about the behavior, not just the concept.
+ placeholder: "Add a configurable advance warning window (e.g. 1-6 in-game hours) that shows a forecast notification for upcoming events. The warning text should hint at the event type and intensity without completely spoiling it."
validations:
required: true
@@ -32,6 +32,7 @@ body:
id: alternatives
attributes:
label: Alternatives Considered
+ description: Have you thought of other ways to solve this? Why are they not good enough?
validations:
required: false
@@ -40,12 +41,11 @@ body:
attributes:
label: Which part of the mod does this relate to?
options:
- - Event System & Triggers
- - Event Types & Effects
- - Notifications & UI
- - Settings / Difficulty
- - Multiplayer
+ - Event Types
+ - Event Frequency / Intensity
+ - HUD / Notifications
- Mod Compatibility
+ - Settings
- Other
validations:
required: true
@@ -54,5 +54,6 @@ body:
id: additional
attributes:
label: Anything Else?
+ description: Screenshots, mockups, references to how other mods handle this, or any extra context.
validations:
required: false
diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml
new file mode 100644
index 0000000..2e96a44
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/other.yml
@@ -0,0 +1,22 @@
+name: Other
+description: Something that doesn't fit the other templates.
+labels: ["needs-triage"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Use this for questions, general feedback, or anything that doesn't fit Bug Report, Compatibility Report, or Feature Request.
+ For questions only, consider [Discussions](https://github.com/TheCodingDad-TisonK/FS25_RandomWorldEvents/discussions) instead.
+ - type: textarea
+ id: description
+ attributes:
+ label: What's on your mind?
+ description: Be as specific as possible.
+ validations:
+ required: true
+ - type: textarea
+ id: additional
+ attributes:
+ label: Anything Else?
+ validations:
+ required: false
diff --git a/.github/workflows/issue-timeout.yml b/.github/workflows/issue-timeout.yml
index a33e2a0..6d30e29 100644
--- a/.github/workflows/issue-timeout.yml
+++ b/.github/workflows/issue-timeout.yml
@@ -40,7 +40,6 @@ jobs:
per_page: 100
});
- // Find when owner last replied
const ownerAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR'];
const ownerComments = comments.data.filter(c =>
ownerAssociations.includes(c.author_association) && c.user.type !== 'Bot'
@@ -51,7 +50,6 @@ jobs:
const age = now - lastOwnerReply;
if (age < twentyFourHours) continue;
- // Check if user replied after the owner's last comment
const author = issue.user.login;
const userRepliedAfter = comments.data.some(c =>
c.user.login === author &&
@@ -60,16 +58,17 @@ jobs:
if (userRepliedAfter) continue;
const closeBody = [
- `Hey @${author} — this issue has been automatically closed because there was no follow-up within **24 hours** of the last response.`,
+ `Hey @${author} — the storm has passed on this one. This issue is being closed automatically because there was no follow-up within **24 hours** of the last response.`,
``,
- `This is not a rejection. If you still have the problem, please **reopen this issue** and include:`,
+ `This is not a rejection! If you still have the problem, please **reopen this issue** and include:`,
``,
- `- The relevant lines from your \`log.txt\``,
+ `- The relevant \`[RWE]\` lines from your \`log.txt\``,
` - Location: \`Documents/My Games/FarmingSimulator2025/log.txt\``,
`- Your mod version (visible in the mod manager)`,
+ `- Which event type is affected, its intensity, and what in-game day it occurred on`,
`- Steps to reproduce the issue`,
``,
- `We look forward to helping you once we have the details!`,
+ `Another event is always around the corner — we look forward to your return!`,
].join('\n');
await github.rest.issues.createComment({
diff --git a/.github/workflows/issue-welcome.yml b/.github/workflows/issue-welcome.yml
index 3e89102..fc68a13 100644
--- a/.github/workflows/issue-welcome.yml
+++ b/.github/workflows/issue-welcome.yml
@@ -28,22 +28,22 @@ jobs:
script: |
const author = context.payload.issue.user.login;
const repoName = context.repo.repo;
- const modName = repoName.replace('FS25_', '').replace(/([A-Z])/g, ' $1').trim();
const body = [
- `Hey @${author}, thanks for opening this issue! 👋`,
+ `Hey @${author}, an unexpected event has arrived — your issue report! ⚡`,
``,
- `@TheCodingDad-TisonK has been notified and will take a look as soon as possible.`,
+ `@TheCodingDad-TisonK has been notified and will investigate as soon as possible.`,
``,
- `**While you wait, please double-check the following:**`,
+ `**To help reproduce the chaos, please confirm:**`,
``,
- `- [ ] You are running the latest version of ${modName} (visible in the mod manager)`,
- `- [ ] Your issue includes relevant lines from \`log.txt\``,
+ `- [ ] You are running the latest version of Random World Events (visible in the mod manager)`,
+ `- [ ] Your issue includes the relevant \`[RWE]\` lines from \`log.txt\``,
` - Log location: \`Documents/My Games/FarmingSimulator2025/log.txt\``,
- ` - Search for \`[${modName}]\` — paste the relevant section in your issue`,
+ ` - Search for \`[RWE]\` and paste the relevant section here`,
+ `- [ ] If this involves a specific event — note the event type, intensity level, and what in-game day it occurred on`,
`- [ ] You have searched [existing issues](https://github.com/${context.repo.owner}/${repoName}/issues) for a similar report`,
``,
- `> **Important:** If this issue is missing a log snippet, it may be closed without investigation. A log is almost always required to reproduce bugs.`,
+ `> **Note:** Issues without a log snippet are difficult to investigate and may be closed. Event trigger bugs especially need log data to trace the sequence.`,
].join('\n');
await github.rest.issues.createComment({
diff --git a/.github/workflows/traffic-stats.yml b/.github/workflows/traffic-stats.yml
new file mode 100644
index 0000000..8a31edb
--- /dev/null
+++ b/.github/workflows/traffic-stats.yml
@@ -0,0 +1,935 @@
+# ============================================================================
+# GitHub Repository Traffic Stats — Reusable Template
+# ============================================================================
+#
+# WHAT THIS IS:
+# A copy-paste-ready GitHub Actions workflow that archives your repository's
+# traffic data (views, clones, downloads, referrers, stars, forks) beyond
+# GitHub's default 14-day retention window, and generates a visual dashboard
+# with charts.
+#
+# HOW TO USE:
+# 1. Copy this file to: .github/workflows/traffic-stats.yml
+# 2. Create a Personal Access Token (classic) with `repo` scope
+# 3. Add it as a repository secret named TRAFFIC_TOKEN
+# 4. Push to your default branch — the workflow runs hourly on schedule
+# 5. After the first run, check the `traffic-stats` branch for your dashboard
+# at .github/traffic/SUMMARY.md
+#
+# WHAT IT COLLECTS:
+# - Hourly: Release download counts (lightweight snapshot)
+# - Every 6h: Full dashboard — views, clones, referrers, stars, forks,
+# watchers, popular paths + chart generation
+# - Manual: Trigger anytime via workflow_dispatch for a full collection
+#
+# DATA STORAGE:
+# All data is committed to an orphan branch called `traffic-stats` so it
+# never clutters your main branch. Data files:
+# - daily.json — Views & clones per day (preserved forever)
+# - downloads.json — Release download snapshots (hourly)
+# - referrers.json — Referrer snapshots (daily)
+# - metadata.json — Stars, forks, watchers (daily)
+# - stats.json — Combined legacy snapshots (6-hourly)
+# - charts/*.png — Auto-generated dashboard charts
+# - SUMMARY.md — Markdown dashboard with embedded charts
+#
+# SMART DEDUPLICATION:
+# Download snapshots are only recorded when the count changes, with a
+# heartbeat entry every 6 hours to keep the timeline alive. Daily data
+# uses date-keyed upserts so re-runs don't create duplicates.
+#
+# REQUIREMENTS:
+# - Repository secret: TRAFFIC_TOKEN (PAT with `repo` scope)
+# - The PAT owner must have push access to the repository
+#
+# CHARTS GENERATED (6 total):
+# 1. Views & Clones — dual-panel time series
+# 2. Total Acquisition per Release — stacked bars + daily clone timeline
+# 3. Referrers — horizontal bar chart
+# 4. Repository Growth — stars, forks, watchers line chart
+# 5. Visitor Engagement — pages per visitor with trend line
+# 6. Conversion Funnel — visitors vs downloaders with conversion rate
+#
+# ============================================================================
+
+name: Traffic Stats Archive
+
+on:
+ schedule:
+ # Hourly: lightweight download snapshot
+ - cron: '0 * * * *'
+ workflow_dispatch: # Allow manual trigger (runs full collection)
+
+permissions:
+ contents: write
+
+jobs:
+ collect-stats:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout traffic-stats branch
+ uses: actions/checkout@v4
+ with:
+ ref: traffic-stats
+ fetch-depth: 0
+ continue-on-error: true
+
+ - name: Create branch if it doesn't exist
+ run: |
+ if ! git rev-parse --verify traffic-stats >/dev/null 2>&1; then
+ git checkout --orphan traffic-stats
+ git rm -rf . 2>/dev/null || true
+ echo "# Traffic Stats" > README.md
+ echo "This branch contains archived traffic data for this repository." >> README.md
+ echo "" >> README.md
+ echo "Hourly download tracking + full dashboard every 6 hours." >> README.md
+ echo "See [SUMMARY.md](.github/traffic/SUMMARY.md) for the latest dashboard." >> README.md
+ git add README.md
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git commit -m "chore: Initialize traffic-stats branch"
+ git push origin traffic-stats
+ fi
+
+ - name: Determine collection mode
+ id: mode
+ run: |
+ HOUR=$(date -u +%H)
+ # Full collection at 00, 06, 12, 18 UTC and on manual trigger
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ] || \
+ [ "$HOUR" = "00" ] || [ "$HOUR" = "06" ] || \
+ [ "$HOUR" = "12" ] || [ "$HOUR" = "18" ]; then
+ echo "full=true" >> $GITHUB_OUTPUT
+ echo "Mode: FULL collection (hour=$HOUR)"
+ else
+ echo "full=false" >> $GITHUB_OUTPUT
+ echo "Mode: DOWNLOAD-ONLY snapshot (hour=$HOUR)"
+ fi
+
+ # ── Always: Hourly download snapshot ────────────────────────
+ - name: Snapshot release downloads
+ env:
+ GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
+ run: |
+ mkdir -p .github/traffic/charts
+
+ TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
+
+ # Fetch release download counts WITH publish dates
+ RELEASES=$(gh api repos/${{ github.repository }}/releases \
+ --jq '[.[] | {tag: .tag_name, published_at: .published_at, assets: [.assets[] | {name: .name, downloads: .download_count}]}]' \
+ 2>/dev/null || echo '[]')
+
+ TOTAL_DL=$(echo "$RELEASES" | jq '[.[].assets[].downloads] | add // 0')
+
+ # Store/update release timeline (maps release tags to their publish dates)
+ RELEASES_TIMELINE=".github/traffic/releases_timeline.json"
+ if [ -f "$RELEASES_TIMELINE" ]; then
+ RT_EXISTING=$(cat "$RELEASES_TIMELINE")
+ else
+ RT_EXISTING='{}'
+ fi
+ # Merge current release data into timeline (preserves historical releases)
+ # Also tracks peak download count per release (survives release deletion)
+ RT_UPDATED=$(echo "$RELEASES" | jq --argjson existing "$RT_EXISTING" '
+ reduce .[] as $r ($existing;
+ ($r.assets | map(.downloads) | add // 0) as $dl |
+ .[$r.tag] = {
+ published_at: $r.published_at,
+ tag: $r.tag,
+ peak_downloads: ([($dl), (.[$r.tag].peak_downloads // 0)] | max)
+ }
+ )
+ ')
+ echo "$RT_UPDATED" > "$RELEASES_TIMELINE"
+
+ # Append to downloads timeline
+ DOWNLOADS_FILE=".github/traffic/downloads.json"
+ if [ -f "$DOWNLOADS_FILE" ]; then
+ DL_EXISTING=$(cat "$DOWNLOADS_FILE")
+ else
+ DL_EXISTING="[]"
+ fi
+
+ # Only append if total changed (avoid duplicate flat-line entries)
+ LAST_TOTAL=$(echo "$DL_EXISTING" | jq '.[-1].total_downloads // -1')
+
+ if [ "$TOTAL_DL" != "$LAST_TOTAL" ] || [ "$DL_EXISTING" = "[]" ]; then
+ DL_UPDATED=$(echo "$DL_EXISTING" | jq \
+ --arg ts "$TIMESTAMP" \
+ --argjson total "$TOTAL_DL" \
+ --argjson releases "$RELEASES" \
+ '. + [{timestamp: $ts, total_downloads: $total, per_release: $releases}]')
+ echo "$DL_UPDATED" > "$DOWNLOADS_FILE"
+ echo "Download snapshot saved: $TOTAL_DL total (changed from $LAST_TOTAL)"
+ else
+ # Still save a heartbeat entry every 6 hours even if unchanged
+ HOUR=$(date -u +%H)
+ if [ "$HOUR" = "00" ] || [ "$HOUR" = "06" ] || \
+ [ "$HOUR" = "12" ] || [ "$HOUR" = "18" ]; then
+ DL_UPDATED=$(echo "$DL_EXISTING" | jq \
+ --arg ts "$TIMESTAMP" \
+ --argjson total "$TOTAL_DL" \
+ --argjson releases "$RELEASES" \
+ '. + [{timestamp: $ts, total_downloads: $total, per_release: $releases}]')
+ echo "$DL_UPDATED" > "$DOWNLOADS_FILE"
+ echo "Heartbeat snapshot saved: $TOTAL_DL total (unchanged, 6hr checkpoint)"
+ else
+ echo "No change in downloads ($TOTAL_DL) — skipping snapshot"
+ fi
+ fi
+
+ # ── Full collection: every 6 hours ──────────────────────────
+ - name: Collect full traffic stats
+ if: steps.mode.outputs.full == 'true'
+ env:
+ GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
+ run: |
+ TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
+ DATE=$(date -u +%Y-%m-%d)
+
+ # ── Fetch all API data ──
+ VIEWS=$(gh api repos/${{ github.repository }}/traffic/views 2>/dev/null || echo '{"count":0,"uniques":0,"views":[]}')
+ CLONES=$(gh api repos/${{ github.repository }}/traffic/clones 2>/dev/null || echo '{"count":0,"uniques":0,"clones":[]}')
+ REFERRERS=$(gh api repos/${{ github.repository }}/traffic/popular/referrers 2>/dev/null || echo '[]')
+ PATHS=$(gh api repos/${{ github.repository }}/traffic/popular/paths 2>/dev/null || echo '[]')
+ RELEASES=$(gh api repos/${{ github.repository }}/releases --jq '[.[] | {tag: .tag_name, assets: [.assets[] | {name: .name, downloads: .download_count}]}]' 2>/dev/null || echo '[]')
+ STARGAZERS=$(gh api repos/${{ github.repository }} --jq '.stargazers_count' 2>/dev/null || echo '0')
+ FORKS=$(gh api repos/${{ github.repository }} --jq '.forks_count' 2>/dev/null || echo '0')
+ WATCHERS=$(gh api repos/${{ github.repository }} --jq '.subscribers_count' 2>/dev/null || echo '0')
+ OPEN_ISSUES=$(gh api repos/${{ github.repository }} --jq '.open_issues_count' 2>/dev/null || echo '0')
+
+ # ── Daily views/clones (preserved beyond 14-day window) ──
+ DAILY_FILE=".github/traffic/daily.json"
+ if [ -f "$DAILY_FILE" ]; then
+ DAILY_EXISTING=$(cat "$DAILY_FILE")
+ else
+ DAILY_EXISTING='{}'
+ fi
+
+ DAILY_UPDATED=$(echo "$VIEWS" | jq --argjson clones "$CLONES" --argjson existing "$DAILY_EXISTING" '
+ $existing as $base |
+ reduce (.views[]? // empty) as $v ($base;
+ ($v.timestamp | split("T")[0]) as $day |
+ .[$day] = (.[$day] // {}) |
+ .[$day].views_total = $v.count |
+ .[$day].views_unique = $v.uniques
+ ) |
+ reduce ($clones.clones[]? // empty) as $c (.;
+ ($c.timestamp | split("T")[0]) as $day |
+ .[$day] = (.[$day] // {}) |
+ .[$day].clones_total = $c.count |
+ .[$day].clones_unique = $c.uniques
+ )
+ ')
+ echo "$DAILY_UPDATED" > "$DAILY_FILE"
+
+ # ── Referrer history (one snapshot per day) ──
+ REFERRER_FILE=".github/traffic/referrers.json"
+ if [ -f "$REFERRER_FILE" ]; then
+ REF_EXISTING=$(cat "$REFERRER_FILE")
+ else
+ REF_EXISTING='{}'
+ fi
+ REF_UPDATED=$(echo "$REF_EXISTING" | jq --arg date "$DATE" --argjson refs "$REFERRERS" '.[$date] = $refs')
+ echo "$REF_UPDATED" > "$REFERRER_FILE"
+
+ # ── Repo metadata (one snapshot per day) ──
+ META_FILE=".github/traffic/metadata.json"
+ if [ -f "$META_FILE" ]; then
+ META_EXISTING=$(cat "$META_FILE")
+ else
+ META_EXISTING="[]"
+ fi
+
+ META_UPDATED=$(echo "$META_EXISTING" | jq --arg date "$DATE" \
+ --argjson stars "$STARGAZERS" --argjson forks "$FORKS" \
+ --argjson watchers "$WATCHERS" --argjson issues "$OPEN_ISSUES" \
+ '[.[] | select(.date != $date)] + [{
+ date: $date, stars: $stars, forks: $forks,
+ watchers: $watchers, open_issues: $issues
+ }] | sort_by(.date)')
+ echo "$META_UPDATED" > "$META_FILE"
+
+ # ── Legacy combined snapshot ──
+ STATS_FILE=".github/traffic/stats.json"
+ if [ -f "$STATS_FILE" ]; then
+ EXISTING=$(cat "$STATS_FILE")
+ else
+ EXISTING="[]"
+ fi
+
+ TODAY_SNAPSHOT=$(jq -n \
+ --arg ts "$TIMESTAMP" --arg date "$DATE" \
+ --argjson views "$VIEWS" --argjson clones "$CLONES" \
+ --argjson referrers "$REFERRERS" --argjson paths "$PATHS" \
+ --argjson releases "$RELEASES" --argjson stars "$STARGAZERS" \
+ --argjson forks "$FORKS" --argjson watchers "$WATCHERS" \
+ '{
+ timestamp: $ts, date: $date,
+ views: { count: $views.count, uniques: $views.uniques },
+ clones: { count: $clones.count, uniques: $clones.uniques },
+ referrers: $referrers, popular_paths: $paths,
+ releases: $releases,
+ stars: $stars, forks: $forks, watchers: $watchers
+ }')
+
+ UPDATED=$(echo "$EXISTING" | jq --arg date "$DATE" --argjson snapshot "$TODAY_SNAPSHOT" \
+ '[.[] | select(.date != $date)] + [$snapshot] | sort_by(.date)')
+ echo "$UPDATED" > "$STATS_FILE"
+
+ # ── Charts: only on full collection ─────────────────────────
+ - name: Set up Python
+ if: steps.mode.outputs.full == 'true'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+
+ - name: Install charting dependencies
+ if: steps.mode.outputs.full == 'true'
+ run: pip install matplotlib
+
+ - name: Generate charts
+ if: steps.mode.outputs.full == 'true'
+ run: |
+ python3 << 'PYEOF'
+ import json
+ import os
+ from datetime import datetime, timedelta
+
+ import matplotlib
+ matplotlib.use('Agg')
+ import matplotlib.pyplot as plt
+ import matplotlib.dates as mdates
+
+ TRAFFIC_DIR = ".github/traffic"
+ CHARTS_DIR = os.path.join(TRAFFIC_DIR, "charts")
+ os.makedirs(CHARTS_DIR, exist_ok=True)
+
+ # ── Shared dark theme (GitHub style) ──
+ plt.rcParams.update({
+ 'figure.facecolor': '#0d1117',
+ 'axes.facecolor': '#161b22',
+ 'axes.edgecolor': '#30363d',
+ 'axes.labelcolor': '#c9d1d9',
+ 'text.color': '#c9d1d9',
+ 'xtick.color': '#8b949e',
+ 'ytick.color': '#8b949e',
+ 'grid.color': '#21262d',
+ 'grid.alpha': 0.8,
+ 'font.size': 11,
+ })
+
+ # ── Chart 1: Views & Clones ──
+ daily_file = os.path.join(TRAFFIC_DIR, "daily.json")
+ if os.path.exists(daily_file):
+ with open(daily_file) as f:
+ daily = json.load(f)
+
+ if daily:
+ dates = sorted(daily.keys())
+ date_objs = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
+ views = [daily[d].get("views_total", 0) or 0 for d in dates]
+ views_uniq = [daily[d].get("views_unique", 0) or 0 for d in dates]
+ clones = [daily[d].get("clones_total", 0) or 0 for d in dates]
+ clones_uniq = [daily[d].get("clones_unique", 0) or 0 for d in dates]
+
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
+ fig.suptitle("Repository Traffic Dashboard", fontsize=16, fontweight='bold', color='#58a6ff')
+
+ ax1.fill_between(date_objs, views, alpha=0.3, color='#58a6ff')
+ ax1.plot(date_objs, views, 'o-', color='#58a6ff', linewidth=2, markersize=5, label='Total Views')
+ ax1.plot(date_objs, views_uniq, 's--', color='#3fb950', linewidth=1.5, markersize=4, label='Unique Visitors')
+ ax1.set_ylabel("Page Views")
+ ax1.legend(loc='upper left', framealpha=0.8)
+ ax1.grid(True, linestyle='--')
+ ax1.set_ylim(bottom=0)
+
+ ax2.fill_between(date_objs, clones, alpha=0.3, color='#d29922')
+ ax2.plot(date_objs, clones, 'o-', color='#d29922', linewidth=2, markersize=5, label='Total Clones')
+ ax2.plot(date_objs, clones_uniq, 's--', color='#f85149', linewidth=1.5, markersize=4, label='Unique Cloners')
+ ax2.set_ylabel("Git Clones")
+ ax2.legend(loc='upper left', framealpha=0.8)
+ ax2.grid(True, linestyle='--')
+ ax2.set_ylim(bottom=0)
+
+ ax2.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
+ ax2.xaxis.set_major_locator(mdates.DayLocator(interval=2))
+ plt.xticks(rotation=45)
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "views_clones.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print("Generated: views_clones.png")
+
+ # ── Chart 2: Total Acquisition per Release Era ──
+ # Combines zip downloads + git clones, attributed to whichever
+ # release was current at the time
+ dl_file = os.path.join(TRAFFIC_DIR, "downloads.json")
+ rt_file = os.path.join(TRAFFIC_DIR, "releases_timeline.json")
+
+ # Load release timeline (tag → publish date + peak downloads)
+ release_eras = []
+ rt = {}
+ if os.path.exists(rt_file):
+ with open(rt_file) as f:
+ rt = json.load(f)
+ for tag, info in rt.items():
+ pub = info.get("published_at")
+ if pub:
+ release_eras.append({
+ "tag": tag,
+ "start": datetime.strptime(pub.split("T")[0], "%Y-%m-%d"),
+ "peak_downloads": info.get("peak_downloads", 0)
+ })
+ release_eras.sort(key=lambda r: r["start"])
+
+ # Load daily clones
+ daily_clones = {}
+ if os.path.exists(daily_file):
+ with open(daily_file) as f:
+ daily = json.load(f)
+ for d, vals in daily.items():
+ daily_clones[d] = vals.get("clones_total", 0) or 0
+
+ # Load download snapshots
+ downloads = []
+ if os.path.exists(dl_file):
+ with open(dl_file) as f:
+ downloads = json.load(f)
+
+ # Helper: which release era does a date belong to?
+ def get_release_era(date_obj):
+ current_tag = None
+ for era in release_eras:
+ if date_obj >= era["start"]:
+ current_tag = era["tag"]
+ return current_tag or (release_eras[0]["tag"] if release_eras else "pre-release")
+
+ # Build per-release-era acquisition totals
+ era_colors = ['#3fb950', '#58a6ff', '#d29922', '#f85149', '#bc8cff',
+ '#56d364', '#79c0ff', '#e3b341', '#ff7b72', '#d2a8ff']
+
+ if release_eras and (daily_clones or downloads):
+ # Aggregate clones per era from daily data
+ era_clones = {}
+ era_clone_days = {} # track daily breakdown for chart
+ for date_str, clone_count in sorted(daily_clones.items()):
+ date_obj = datetime.strptime(date_str, "%Y-%m-%d")
+ era_tag = get_release_era(date_obj)
+ era_clones[era_tag] = era_clones.get(era_tag, 0) + clone_count
+ if era_tag not in era_clone_days:
+ era_clone_days[era_tag] = []
+ era_clone_days[era_tag].append((date_obj, clone_count))
+
+ # Get latest download total per release from most recent snapshot
+ era_downloads = {}
+ if downloads:
+ latest = downloads[-1]
+ for rel in (latest.get("per_release") or latest.get("releases", [])):
+ era_downloads[rel["tag"]] = sum(a["downloads"] for a in rel.get("assets", []))
+
+ # Fallback: use peak_downloads from timeline for deleted releases
+ for era in release_eras:
+ if era["tag"] not in era_downloads and era.get("peak_downloads", 0) > 0:
+ era_downloads[era["tag"]] = era["peak_downloads"]
+
+ # ── Main chart: stacked bars per release era ──
+ tags = [era["tag"] for era in release_eras]
+ clone_vals = [era_clones.get(t, 0) for t in tags]
+ dl_vals = [era_downloads.get(t, 0) for t in tags]
+ total_vals = [c + d for c, d in zip(clone_vals, dl_vals)]
+
+ fig, (ax_bars, ax_timeline) = plt.subplots(2, 1, figsize=(12, 9),
+ gridspec_kw={'height_ratios': [1, 1.2]})
+ fig.suptitle("Total Acquisition per Release", fontsize=16, fontweight='bold', color='#58a6ff')
+
+ # Top: stacked bar chart per release
+ x = list(range(len(tags)))
+ bar_w = 0.5
+ bars_clones = ax_bars.bar(x, clone_vals, bar_w, color='#3fb950', alpha=0.8, label='Git Clones')
+ bars_dls = ax_bars.bar(x, dl_vals, bar_w, bottom=clone_vals, color='#d29922', alpha=0.8, label='Zip Downloads')
+
+ ax_bars.set_xticks(x)
+ ax_bars.set_xticklabels(tags, fontsize=11)
+ ax_bars.set_ylabel("Total Acquisitions")
+ ax_bars.legend(loc='upper left', framealpha=0.8)
+ ax_bars.grid(True, axis='y', linestyle='--')
+ ax_bars.set_ylim(bottom=0)
+
+ # Value labels on bars
+ for i, (ct, dt, tt) in enumerate(zip(clone_vals, dl_vals, total_vals)):
+ # Clone count inside green bar
+ if ct > 0:
+ ax_bars.text(i, ct/2, f'{ct} clones', ha='center', va='center',
+ fontsize=10, color='white', fontweight='bold')
+ # Download count inside gold bar
+ if dt > 0:
+ ax_bars.text(i, ct + dt/2, f'{dt} zips', ha='center', va='center',
+ fontsize=10, color='white', fontweight='bold')
+ # Total on top
+ ax_bars.text(i, tt + max(total_vals)*0.02, str(tt), ha='center',
+ fontsize=12, fontweight='bold', color='#c9d1d9')
+
+ # Bottom: daily clones timeline with release era shading
+ all_dates = sorted(daily_clones.keys())
+ if all_dates:
+ date_objs = [datetime.strptime(d, "%Y-%m-%d") for d in all_dates]
+ clone_series = [daily_clones.get(d, 0) for d in all_dates]
+
+ ax_timeline.bar(date_objs, clone_series, width=0.8, color='#3fb950', alpha=0.6, label='Daily Clones')
+
+ # Shade release eras with colors + labels
+ for i, era in enumerate(release_eras):
+ era_start = era["start"]
+ # Era ends when next release starts, or today
+ if i + 1 < len(release_eras):
+ era_end = release_eras[i+1]["start"]
+ else:
+ era_end = max(date_objs) + timedelta(days=1)
+ color = era_colors[i % len(era_colors)]
+ ax_timeline.axvspan(era_start, era_end, alpha=0.08, color=color)
+ # Label at top of shaded region
+ mid = era_start + (era_end - era_start) / 2
+ ax_timeline.text(mid, ax_timeline.get_ylim()[1] if ax_timeline.get_ylim()[1] > 0 else max(clone_series) * 0.95,
+ era["tag"], ha='center', va='top', fontsize=10,
+ color=color, fontweight='bold', alpha=0.9)
+ # Vertical line at release boundary
+ ax_timeline.axvline(x=era_start, color=color, linestyle='--', alpha=0.5, linewidth=1)
+
+ ax_timeline.set_ylabel("Daily Git Clones")
+ ax_timeline.set_xlabel("")
+ ax_timeline.grid(True, axis='y', linestyle='--')
+ ax_timeline.set_ylim(bottom=0)
+ ax_timeline.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
+ ax_timeline.xaxis.set_major_locator(mdates.DayLocator(interval=2))
+ plt.xticks(rotation=45)
+
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "downloads.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+
+ total_all = sum(total_vals)
+ print(f"Generated: downloads.png ({len(tags)} releases, {total_all} total acquisitions)")
+
+ elif downloads:
+ # No release timeline yet — fallback to simple download chart
+ if len(downloads) >= 2:
+ timestamps = [datetime.strptime(d["timestamp"], "%Y-%m-%dT%H:%M:%SZ") for d in downloads]
+ totals = [d["total_downloads"] for d in downloads]
+
+ fig, ax = plt.subplots(figsize=(12, 4))
+ fig.suptitle("Release Downloads", fontsize=14, fontweight='bold', color='#58a6ff')
+ ax.fill_between(timestamps, totals, alpha=0.2, color='#3fb950')
+ ax.plot(timestamps, totals, 'o-', color='#3fb950', linewidth=2, markersize=4)
+ ax.set_ylabel("Total Downloads")
+ ax.set_ylim(bottom=0)
+ ax.grid(True, linestyle='--')
+ ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d %H:%M'))
+ plt.xticks(rotation=45)
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "downloads.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print(f"Generated: downloads.png (fallback, {len(downloads)} snapshots)")
+
+ elif len(downloads) == 1:
+ d = downloads[0]
+ total = d["total_downloads"]
+ releases = d.get("per_release") or d.get("releases", [])
+ labels, values = [], []
+ for rel in releases:
+ for asset in rel.get("assets", []):
+ labels.append(f'{rel.get("tag","?")}\n{asset["name"]}')
+ values.append(asset["downloads"])
+ if not labels:
+ labels, values = ["Total"], [total]
+
+ fig, ax = plt.subplots(figsize=(8, 4))
+ fig.suptitle("Release Downloads", fontsize=14, fontweight='bold', color='#58a6ff')
+ bars = ax.bar(labels, values, color='#3fb950', width=0.4)
+ ax.set_ylabel("Downloads")
+ ax.grid(True, axis='y', linestyle='--')
+ ax.set_ylim(bottom=0)
+ for bar, val in zip(bars, values):
+ ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.3,
+ str(val), ha='center', fontsize=14, fontweight='bold', color='#3fb950')
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "downloads.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print(f"Generated: downloads.png (single snapshot: {total})")
+
+ # ── Chart 3: Referrers ──
+ ref_file = os.path.join(TRAFFIC_DIR, "referrers.json")
+ if os.path.exists(ref_file):
+ with open(ref_file) as f:
+ referrers = json.load(f)
+
+ if referrers:
+ latest_date = sorted(referrers.keys())[-1]
+ refs = referrers[latest_date]
+
+ if refs:
+ names = [r["referrer"] for r in refs]
+ counts = [r["count"] for r in refs]
+ colors = ['#58a6ff', '#3fb950', '#d29922', '#f85149', '#bc8cff',
+ '#79c0ff', '#56d364', '#e3b341', '#ff7b72', '#d2a8ff']
+
+ fig, ax = plt.subplots(figsize=(8, 5))
+ fig.suptitle(f"Traffic Referrers ({latest_date})", fontsize=14, fontweight='bold', color='#58a6ff')
+ bars = ax.barh(names[::-1], counts[::-1], color=colors[:len(names)][::-1])
+ ax.set_xlabel("Page Views")
+ ax.grid(True, axis='x', linestyle='--')
+
+ for bar, count in zip(bars, counts[::-1]):
+ ax.text(bar.get_width() + max(counts)*0.02, bar.get_y() + bar.get_height()/2,
+ str(count), va='center', color='#c9d1d9', fontsize=10)
+
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "referrers.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print("Generated: referrers.png")
+
+ # ── Chart 4: Stars/Forks growth (always line chart) ──
+ meta_file = os.path.join(TRAFFIC_DIR, "metadata.json")
+ if os.path.exists(meta_file):
+ with open(meta_file) as f:
+ metadata = json.load(f)
+
+ if metadata:
+ dates = [datetime.strptime(m["date"], "%Y-%m-%d") for m in metadata]
+ stars = [m.get("stars", 0) for m in metadata]
+ forks = [m.get("forks", 0) for m in metadata]
+ watchers = [m.get("watchers", 0) for m in metadata]
+
+ fig, ax = plt.subplots(figsize=(12, 4))
+ fig.suptitle("Repository Growth", fontsize=14, fontweight='bold', color='#58a6ff')
+ ax.plot(dates, stars, 'o-', color='#d29922', linewidth=2, markersize=6, label='Stars')
+ ax.plot(dates, forks, 's-', color='#58a6ff', linewidth=2, markersize=5, label='Forks')
+ ax.plot(dates, watchers, '^-', color='#3fb950', linewidth=2, markersize=5, label='Watchers')
+ ax.set_ylabel("Count")
+ ax.legend(loc='upper left', framealpha=0.8)
+ ax.grid(True, linestyle='--')
+ ax.set_ylim(bottom=0)
+ ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
+ # Explicitly set ticks to actual dates (auto-locator misses with few points)
+ ax.set_xticks(dates)
+ plt.xticks(rotation=45)
+
+ # Value labels at each point
+ for d, s, f, w in zip(dates, stars, forks, watchers):
+ ax.annotate(str(s), (d, s), textcoords="offset points",
+ xytext=(0, 8), ha='center', fontsize=9, color='#d29922', fontweight='bold')
+ if f > 0:
+ ax.annotate(str(f), (d, f), textcoords="offset points",
+ xytext=(0, 8), ha='center', fontsize=9, color='#58a6ff', fontweight='bold')
+ if w > 0:
+ ax.annotate(str(w), (d, w), textcoords="offset points",
+ xytext=(0, -14), ha='center', fontsize=9, color='#3fb950', fontweight='bold')
+
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "growth.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print(f"Generated: growth.png ({len(metadata)} data points)")
+
+ # ── Chart 5: Engagement (pages per visitor) ──
+ if os.path.exists(daily_file):
+ with open(daily_file) as f:
+ daily = json.load(f)
+
+ if daily:
+ dates = sorted(daily.keys())
+ date_objs = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
+ views = [daily[d].get("views_total", 0) or 0 for d in dates]
+ uniques = [daily[d].get("views_unique", 0) or 0 for d in dates]
+ pages_per_visitor = [v / u if u > 0 else 0 for v, u in zip(views, uniques)]
+
+ fig, ax1 = plt.subplots(figsize=(12, 6))
+ fig.suptitle("Visitor Engagement — Are People Exploring?",
+ fontsize=15, fontweight='bold', color='#58a6ff')
+
+ # Stacked area: unique visitors vs total views
+ ax1.fill_between(date_objs, uniques, alpha=0.4, color='#3fb950', label='Unique Visitors')
+ ax1.fill_between(date_objs, views, alpha=0.2, color='#58a6ff', label='Total Page Views')
+ ax1.plot(date_objs, views, '-', color='#58a6ff', linewidth=1.5, alpha=0.7)
+ ax1.plot(date_objs, uniques, '-', color='#3fb950', linewidth=1.5, alpha=0.7)
+ ax1.set_ylabel("Count", color='#c9d1d9')
+ ax1.set_ylim(bottom=0)
+ ax1.grid(True, linestyle='--')
+
+ # Pages per visitor on secondary axis
+ ax2 = ax1.twinx()
+ ax2.plot(date_objs, pages_per_visitor, 'D-', color='#d29922', linewidth=2.5,
+ markersize=7, label='Pages / Visitor', zorder=5)
+ ax2.set_ylabel("Avg Pages per Visitor", color='#d29922')
+ ax2.set_ylim(bottom=0)
+
+ # Add value labels on the engagement line
+ for i, (d, ppv) in enumerate(zip(date_objs, pages_per_visitor)):
+ if ppv > 0:
+ ax2.annotate(f'{ppv:.1f}', (d, ppv),
+ textcoords="offset points", xytext=(0, 10),
+ ha='center', fontsize=9, color='#d29922', fontweight='bold')
+
+ # Average engagement line
+ valid_ppv = [p for p in pages_per_visitor if p > 0]
+ if valid_ppv:
+ avg_ppv = sum(valid_ppv) / len(valid_ppv)
+ ax2.axhline(y=avg_ppv, color='#d29922', linestyle=':', alpha=0.5, linewidth=1)
+ ax2.text(date_objs[-1], avg_ppv, f' avg: {avg_ppv:.1f}',
+ va='bottom', color='#d29922', fontsize=9, alpha=0.7)
+
+ # Combine legends
+ lines1, labels1 = ax1.get_legend_handles_labels()
+ lines2, labels2 = ax2.get_legend_handles_labels()
+ ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', framealpha=0.8)
+
+ ax1.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
+ ax1.xaxis.set_major_locator(mdates.DayLocator(interval=2))
+ plt.xticks(rotation=45)
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "engagement.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+ print(f"Generated: engagement.png (avg {avg_ppv:.1f} pages/visitor)" if valid_ppv else "Generated: engagement.png")
+
+ # ── Chart 6: Conversion funnel (visitor → clone/download) ──
+ if os.path.exists(daily_file):
+ with open(daily_file) as f:
+ daily = json.load(f)
+
+ # Compute daily download deltas from cumulative snapshots
+ daily_dl_deltas = {}
+ if os.path.exists(dl_file):
+ with open(dl_file) as f:
+ downloads = json.load(f)
+ if len(downloads) >= 2:
+ for i in range(1, len(downloads)):
+ prev = downloads[i-1]
+ curr = downloads[i]
+ delta = max(0, curr["total_downloads"] - prev["total_downloads"])
+ if delta > 0:
+ day = curr["timestamp"].split("T")[0]
+ daily_dl_deltas[day] = daily_dl_deltas.get(day, 0) + delta
+
+ if daily:
+ dates = sorted(daily.keys())
+ date_objs = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
+ visitors = [daily[d].get("views_unique", 0) or 0 for d in dates]
+ cloners = [daily[d].get("clones_unique", 0) or 0 for d in dates]
+ dls = [daily_dl_deltas.get(d, 0) for d in dates]
+ # Combined acquisitions = unique cloners + download deltas
+ acquisitions = [c + dl for c, dl in zip(cloners, dls)]
+ # Conversion rate
+ conversion = [a / v * 100 if v > 0 else 0 for a, v in zip(acquisitions, visitors)]
+
+ fig, ax1 = plt.subplots(figsize=(12, 6))
+ fig.suptitle("Conversion Funnel — Visitors Who Download",
+ fontsize=15, fontweight='bold', color='#58a6ff')
+
+ # Grouped bars: visitors vs acquisitions
+ bar_width = 0.35
+ x_indices = list(range(len(dates)))
+ x_visitors = [x - bar_width/2 for x in x_indices]
+ x_acquired = [x + bar_width/2 for x in x_indices]
+
+ ax1.bar(x_visitors, visitors, bar_width, color='#58a6ff', alpha=0.7, label='Unique Visitors')
+ # Stack clones and downloads in the acquired bar
+ ax1.bar(x_acquired, cloners, bar_width, color='#3fb950', alpha=0.8, label='Unique Cloners')
+ if any(dl > 0 for dl in dls):
+ ax1.bar(x_acquired, dls, bar_width, bottom=cloners, color='#d29922', alpha=0.8, label='Release Downloads')
+
+ ax1.set_ylabel("People")
+ ax1.set_ylim(bottom=0)
+ ax1.grid(True, axis='y', linestyle='--')
+
+ # X-axis labels
+ ax1.set_xticks(x_indices)
+ short_dates = [datetime.strptime(d, "%Y-%m-%d").strftime('%b %d') for d in dates]
+ ax1.set_xticklabels(short_dates, rotation=45, ha='right')
+
+ # Conversion rate line on secondary axis
+ ax2 = ax1.twinx()
+ ax2.plot(x_indices, conversion, 'D-', color='#f85149', linewidth=2.5,
+ markersize=8, label='Conversion %', zorder=5)
+ ax2.set_ylabel("Conversion Rate %", color='#f85149')
+ ax2.set_ylim(bottom=0, top=max(max(conversion) * 1.3, 10) if conversion else 100)
+
+ # Value labels on conversion points
+ for x, pct in zip(x_indices, conversion):
+ if pct > 0:
+ ax2.annotate(f'{pct:.0f}%', (x, pct),
+ textcoords="offset points", xytext=(0, 12),
+ ha='center', fontsize=10, color='#f85149', fontweight='bold')
+
+ # Average conversion line
+ valid_conv = [c for c in conversion if c > 0]
+ if valid_conv:
+ avg_conv = sum(valid_conv) / len(valid_conv)
+ ax2.axhline(y=avg_conv, color='#f85149', linestyle=':', alpha=0.4, linewidth=1)
+ ax2.text(x_indices[-1] + 0.1, avg_conv, f' avg: {avg_conv:.0f}%',
+ va='center', color='#f85149', fontsize=9, alpha=0.7)
+
+ # Combine legends
+ lines1, labels1 = ax1.get_legend_handles_labels()
+ lines2, labels2 = ax2.get_legend_handles_labels()
+ ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', framealpha=0.8)
+
+ fig.tight_layout()
+ fig.savefig(os.path.join(CHARTS_DIR, "conversion.png"), dpi=150, bbox_inches='tight')
+ plt.close()
+
+ # Print summary
+ total_visitors = sum(visitors)
+ total_acquired = sum(acquisitions)
+ overall_conv = (total_acquired / total_visitors * 100) if total_visitors > 0 else 0
+ print(f"Generated: conversion.png ({overall_conv:.0f}% overall conversion)")
+
+ print("Chart generation complete!")
+ PYEOF
+
+ # ── Summary: only on full collection ────────────────────────
+ - name: Generate summary dashboard
+ if: steps.mode.outputs.full == 'true'
+ env:
+ GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
+ run: |
+ SUMMARY_FILE=".github/traffic/SUMMARY.md"
+ DATE=$(date -u +%Y-%m-%d)
+ TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
+
+ VIEWS=$(gh api repos/${{ github.repository }}/traffic/views 2>/dev/null || echo '{"count":0,"uniques":0}')
+ CLONES=$(gh api repos/${{ github.repository }}/traffic/clones 2>/dev/null || echo '{"count":0,"uniques":0}')
+ REFERRERS=$(gh api repos/${{ github.repository }}/traffic/popular/referrers 2>/dev/null || echo '[]')
+ PATHS=$(gh api repos/${{ github.repository }}/traffic/popular/paths 2>/dev/null || echo '[]')
+ # Read download total from our own data (gh api --jq has issues with nested arrays)
+ TOTAL_DL=$(jq '.[-1].total_downloads // 0' .github/traffic/downloads.json 2>/dev/null || echo '0')
+ STARGAZERS=$(gh api repos/${{ github.repository }} --jq '.stargazers_count' 2>/dev/null || echo '0')
+ FORKS=$(gh api repos/${{ github.repository }} --jq '.forks_count' 2>/dev/null || echo '0')
+ WATCHERS=$(gh api repos/${{ github.repository }} --jq '.subscribers_count' 2>/dev/null || echo '0')
+
+ DAYS_TRACKED=$(jq 'length' .github/traffic/metadata.json 2>/dev/null || echo '1')
+ DL_SNAPSHOTS=$(jq 'length' .github/traffic/downloads.json 2>/dev/null || echo '1')
+
+ {
+ echo "# Repository Traffic Dashboard"
+ echo ""
+ echo "**Last updated:** ${TIMESTAMP}"
+ echo "**Days tracked:** ${DAYS_TRACKED} | **Download snapshots:** ${DL_SNAPSHOTS} (hourly)"
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Views & Clones (14-day window, preserved forever)"
+ echo ""
+ echo ""
+ echo ""
+ echo "| Metric | 14-Day Total | Unique |"
+ echo "|--------|-------------|--------|"
+ echo "| Page Views | $(echo "$VIEWS" | jq '.count') | $(echo "$VIEWS" | jq '.uniques') |"
+ echo "| Git Clones | $(echo "$CLONES" | jq '.count') | $(echo "$CLONES" | jq '.uniques') |"
+ echo ""
+ TOTAL_VIEWS=$(echo "$VIEWS" | jq '.count')
+ UNIQUE_VISITORS=$(echo "$VIEWS" | jq '.uniques')
+ if [ "$UNIQUE_VISITORS" -gt 0 ] 2>/dev/null; then
+ AVG_PAGES=$(echo "scale=1; $TOTAL_VIEWS / $UNIQUE_VISITORS" | bc)
+ echo "> **Engagement:** ${AVG_PAGES} pages per visitor (14-day avg)"
+ echo ""
+ fi
+ echo "---"
+ echo ""
+ echo "## Visitor Engagement"
+ echo ""
+ echo ""
+ echo ""
+ echo "> Higher = visitors exploring more pages. 1.0 = bounce. 3.0+ = deeply engaged."
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Conversion Funnel"
+ echo ""
+ echo ""
+ echo ""
+ UNIQUE_CLONERS=$(echo "$CLONES" | jq '.uniques')
+ if [ "$UNIQUE_VISITORS" -gt 0 ] 2>/dev/null; then
+ CONV_ACQUIRED=$((UNIQUE_CLONERS + TOTAL_DL))
+ CONV_PCT=$(echo "scale=1; $CONV_ACQUIRED * 100 / $UNIQUE_VISITORS" | bc)
+ echo "> **14-day conversion:** ${CONV_ACQUIRED} of ${UNIQUE_VISITORS} visitors cloned or downloaded (**${CONV_PCT}%**)"
+ echo ">"
+ echo "> Unique cloners: ${UNIQUE_CLONERS} | Release downloads: ${TOTAL_DL}"
+ fi
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Total Acquisition per Release (Downloads + Clones)"
+ echo ""
+ echo ""
+ echo ""
+ TOTAL_CLONES_14D=$(echo "$CLONES" | jq '.count')
+ TOTAL_ACQUIRED=$((TOTAL_DL + TOTAL_CLONES_14D))
+ echo "| Channel | Count |"
+ echo "|---------|-------|"
+ echo "| Zip Downloads | ${TOTAL_DL} |"
+ echo "| Git Clones (14-day) | ${TOTAL_CLONES_14D} |"
+ echo "| **Total Acquisitions** | **${TOTAL_ACQUIRED}** |"
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Referrers"
+ echo ""
+ echo ""
+ echo ""
+ echo "| Source | Views | Unique |"
+ echo "|--------|-------|--------|"
+ echo "$REFERRERS" | jq -r '.[] | "| \(.referrer) | \(.count) | \(.uniques) |"' 2>/dev/null || echo "| No data | - | - |"
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Repository Growth"
+ echo ""
+ echo ""
+ echo ""
+ echo "| Metric | Current |"
+ echo "|--------|---------|"
+ echo "| Stars | ${STARGAZERS} |"
+ echo "| Forks | ${FORKS} |"
+ echo "| Watchers | ${WATCHERS} |"
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Top Pages (14-day)"
+ echo ""
+ echo "| Page | Views | Unique |"
+ echo "|------|-------|--------|"
+ echo "$PATHS" | jq -r '.[:10][] | "| `\(.path)` | \(.count) | \(.uniques) |"' 2>/dev/null || echo "| No data | - | - |"
+ echo ""
+ echo "---"
+ echo ""
+ echo "## Data Files"
+ echo ""
+ echo "| File | Description | Granularity |"
+ echo "|------|-------------|-------------|"
+ echo "| [daily.json](daily.json) | Views & clones per day (never expires) | Daily |"
+ echo "| [downloads.json](downloads.json) | Release download snapshots | Hourly |"
+ echo "| [referrers.json](referrers.json) | Referrer snapshots | Daily |"
+ echo "| [metadata.json](metadata.json) | Stars, forks, watchers | Daily |"
+ echo "| [stats.json](stats.json) | Combined legacy snapshots | 6-hourly |"
+ echo ""
+ echo "---"
+ echo "*Hourly download tracking + full dashboard with engagement metrics every 6 hours*"
+ echo "*Auto-generated by [traffic-stats.yml](../../.github/workflows/traffic-stats.yml)*"
+ } > "$SUMMARY_FILE"
+
+ # ── Commit ──────────────────────────────────────────────────
+ - name: Commit and push
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git add .github/traffic/
+ if git diff --cached --quiet; then
+ echo "No changes to commit"
+ else
+ MODE="${{ steps.mode.outputs.full }}"
+ if [ "$MODE" = "true" ]; then
+ git commit -m "chore: Full traffic snapshot $(date -u +%Y-%m-%d_%H:%M)"
+ else
+ git commit -m "chore: Download snapshot $(date -u +%Y-%m-%d_%H:%M)"
+ fi
+ git push origin traffic-stats
+ fi
diff --git a/RandomWorldEvents.lua b/RandomWorldEvents.lua
index d80ef98..3a0f1fe 100644
--- a/RandomWorldEvents.lua
+++ b/RandomWorldEvents.lua
@@ -209,7 +209,14 @@ function RandomWorldEvents:createSettingsManager()
settingsObject.physics.suspensionStiffness = xml:getFloat(manager.XMLTAG..".physics.suspensionStiffness", manager.defaultConfig.physics.suspensionStiffness)
settingsObject.physics.showPhysicsInfo = xml:getBool(manager.XMLTAG..".physics.showPhysicsInfo", manager.defaultConfig.physics.showPhysicsInfo)
settingsObject.physics.debugMode = xml:getBool(manager.XMLTAG..".physics.debugMode", manager.defaultConfig.physics.debugMode)
-
+
+ -- Load saved event state (temp fields; applied in loadFinished when g_currentMission.time is valid)
+ local savedEvent = xml:getString(manager.XMLTAG..".eventState.activeEvent", "")
+ settingsObject._savedActiveEvent = savedEvent ~= "" and savedEvent or nil
+ settingsObject._savedRemainingMs = xml:getFloat(manager.XMLTAG..".eventState.remainingMs", 0)
+ settingsObject._savedCooldownRemainingMs = xml:getFloat(manager.XMLTAG..".eventState.cooldownRemainingMs", 0)
+ settingsObject._savedMidpointFired = xml:getBool(manager.XMLTAG..".eventState.midpointFired", false)
+
xml:delete()
return
end
@@ -271,7 +278,20 @@ function RandomWorldEvents:createSettingsManager()
xml:setFloat(manager.XMLTAG..".physics.suspensionStiffness", settingsObject.physics.suspensionStiffness)
xml:setBool(manager.XMLTAG..".physics.showPhysicsInfo", settingsObject.physics.showPhysicsInfo)
xml:setBool(manager.XMLTAG..".physics.debugMode", settingsObject.physics.debugMode)
-
+
+ -- Save active event state as remaining time so timers survive reload
+ local es = settingsObject.EVENT_STATE
+ if es and es.activeEvent then
+ xml:setString(manager.XMLTAG..".eventState.activeEvent", es.activeEvent)
+ local remaining = math.max(0, (es.eventStartTime + (es.eventDuration or 0)) - g_currentMission.time)
+ xml:setFloat(manager.XMLTAG..".eventState.remainingMs", remaining)
+ xml:setBool(manager.XMLTAG..".eventState.midpointFired", es.midpointFired or false)
+ else
+ xml:setString(manager.XMLTAG..".eventState.activeEvent", "")
+ end
+ local esCooldown = es and math.max(0, (es.cooldownUntil or 0) - g_currentMission.time) or 0
+ xml:setFloat(manager.XMLTAG..".eventState.cooldownRemainingMs", esCooldown)
+
xml:save()
xml:delete()
self:dbg("Settings saved successfully")
@@ -1109,6 +1129,24 @@ local function loadFinished(mission, ...)
g_inputBinding:endActionEventsModification()
end
+
+ -- Restore active event state saved before this session ended.
+ -- g_currentMission.time is valid here; we use remaining-time offsets
+ -- instead of absolute timestamps so reloads work correctly.
+ if g_RandomWorldEvents and g_RandomWorldEvents._savedActiveEvent then
+ local mgr = g_RandomWorldEvents
+ local es = mgr.EVENT_STATE
+ es.activeEvent = mgr._savedActiveEvent
+ es.eventStartTime = g_currentMission.time
+ es.eventDuration = mgr._savedRemainingMs or 0
+ es.midpointFired = mgr._savedMidpointFired or false
+ es.cooldownUntil = g_currentMission.time + (mgr._savedCooldownRemainingMs or 0)
+ mgr._savedActiveEvent = nil
+ mgr._savedRemainingMs = nil
+ mgr._savedCooldownRemainingMs = nil
+ mgr._savedMidpointFired = nil
+ Logging.info("[RWE] Resumed active event from save: " .. tostring(es.activeEvent))
+ end
end
end
diff --git a/modDesc.xml b/modDesc.xml
index 38a5411..3541dcc 100644
--- a/modDesc.xml
+++ b/modDesc.xml
@@ -14,6 +14,7 @@
Eventos Mundiais Aleatórios
Випадкові світові події
Случайные мировые события
+ Random World Events
Adds random events, physics overhaul, and configurable settings.
@@ -26,6 +27,7 @@
Adiciona eventos aleatórios, revisão de física e configurações personalizáveis.
Додає випадкові події, переробку фізики та настроювані параметри.
Добавляет случайные события, переработку физики и настраиваемые параметры.
+ Tilføjer tilfældige hændelser, fysikopdateringer og konfigurerbare indstillinger.
icon.dds
@@ -81,6 +83,7 @@
Eventos Mundiais Aleatórios
Випадкові світові події
Случайные мировые события
+ Random World Events
@@ -94,6 +97,7 @@
Ativar eventos
Увімкнути події
Включить события
+ Aktiver hændelser
@@ -107,180 +111,581 @@
Ativar ou desativar todos os eventos aleatórios
Увімкнути або вимкнути всі випадкові події
Включить или выключить все случайные события
+ Aktivér eller deaktivér alle tilfældige hændelser
Event Timing
Розклад подій
+ Interval for hændelser
+
+ Event Zeitpunkt
+ [EN] Event Timing
+ [EN] Event Timing
+ [EN] Event Timing
+ [EN] Event Timing
+ [EN] Event Timing
+
[EN] Event Timing
+ [EN] Event Timing
Notifications & HUD
Сповіщення та HUD
+ Notifikationer & HUD
+
+ HUD Benachrichtigung
+ [EN] Notifications & HUD
+ [EN] Notifications & HUD
+ [EN] Notifications & HUD
+ [EN] Notifications & HUD
+ [EN] Notifications & HUD
+
[EN] Notifications & HUD
+ [EN] Notifications & HUD
Event Categories
Категорії подій
+ Hændelsestyper
+
+ Eventkategorien
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+
[EN] Event Categories
+ [EN] Event Categories
Physics Override
Налаштування фізики
+ Fysikoverstyring
+
+ Überschreibung der Mechanik
+ [EN] Physics Override
+ [EN] Physics Override
+ [EN] Physics Override
+ [EN] Physics Override
+ [EN] Physics Override
+
[EN] Physics Override
+ [EN] Physics Override
Debug
Налагодження
+ Fejlfinding
+
+ Debug
+ [EN] Debug
+ [EN] Debug
+ [EN] Debug
+ [EN] Debug
+ [EN] Debug
+
[EN] Debug
+ [EN] Debug
Frequency
Частота
+ Frekvens
+
+ Häufigkeit
+ [EN] Frequency
+ [EN] Frequency
+ [EN] Frequency
+ [EN] Frequency
+ [EN] Frequency
+
[EN] Frequency
+ [EN] Frequency
How often events fire (1 = rare, 10 = frequent)
Як часто виникають події (1 = рідко, 10 = часто)
+ Hvor ofte hændelser udløses (1 = sjældent, 10 = ofte)
+
+ Wie häufig Events kommen (1 = selten, 10 = häufig)
+ [EN] How often events fire (1 = rare, 10 = frequent)
+ [EN] How often events fire (1 = rare, 10 = frequent)
+ [EN] How often events fire (1 = rare, 10 = frequent)
+ [EN] How often events fire (1 = rare, 10 = frequent)
+ [EN] How often events fire (1 = rare, 10 = frequent)
+
[EN] How often events fire (1 = rare, 10 = frequent)
+ [EN] How often events fire (1 = rare, 10 = frequent)
Intensity
Інтенсивність
+ Styrke
+
+ Intensität
+ [EN] Intensity
+ [EN] Intensity
+ [EN] Intensity
+ [EN] Intensity
+ [EN] Intensity
+
[EN] Intensity
+ [EN] Intensity
Strength of event effects (1 = mild, 5 = extreme)
Сила ефектів подій (1 = слабка, 5 = екстремальна)
+ Styrken af hændelseseffekter (1 = mild, 5 = ekstrem)
+
+ Stärke der Weltereignisse (1 = schwach, 5 = extrem)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
+
[EN] Strength of event effects (1 = mild, 5 = extreme)
+ [EN] Strength of event effects (1 = mild, 5 = extreme)
Cooldown
Перерва
+ Cooldown
+
+ Abklingzeit
+ [EN] Cooldown
+ [EN] Cooldown
+ [EN] Cooldown
+ [EN] Cooldown
+ [EN] Cooldown
+
[EN] Cooldown
+ [EN] Cooldown
Minimum in-game time between events
Мінімальний ігровий час між подіями
+ Minimum in-game tid mellem hændelser
+
+ Mindestzeit (Ingame) zwischen den Ereignissen
+ [EN] Minimum in-game time between events
+ [EN] Minimum in-game time between events
+ [EN] Minimum in-game time between events
+ [EN] Minimum in-game time between events
+ [EN] Minimum in-game time between events
+
[EN] Minimum in-game time between events
+ [EN] Minimum in-game time between events
Show Notifications
Показувати сповіщення
+ Vis Notifikationer
+
+ Zeige Benachrichtigungen
+ [EN] Show Notifications
+ [EN] Show Notifications
+ [EN] Show Notifications
+ [EN] Show Notifications
+ [EN] Show Notifications
+
[EN] Show Notifications
+ [EN] Show Notifications
Display event notifications on screen
Відображати сповіщення про події на екрані
+ Vis hændelsesnotifikationer på skærmen
+
+ Zeige die Benachrichtigungen auf dem Bildschirm
+ [EN] Display event notifications on screen
+ [EN] Display event notifications on screen
+ [EN] Display event notifications on screen
+ [EN] Display event notifications on screen
+ [EN] Display event notifications on screen
+
[EN] Display event notifications on screen
+ [EN] Display event notifications on screen
Show Warnings
Показувати попередження
+ Vis Advarsler
+
+ Zeige Warnungen
+ [EN] Show Warnings
+ [EN] Show Warnings
+ [EN] Show Warnings
+ [EN] Show Warnings
+ [EN] Show Warnings
+
[EN] Show Warnings
+ [EN] Show Warnings
Show event warning messages
Відображати попереджувальні повідомлення про події
+ Vis hændelsesadvarsler
+
+ Zeige Warnungen der Weltereignisse
+ [EN] Show event warning messages
+ [EN] Show event warning messages
+ [EN] Show event warning messages
+ [EN] Show event warning messages
+ [EN] Show event warning messages
+
[EN] Show event warning messages
+ [EN] Show event warning messages
Show HUD Panel
Показати панель HUD
+ Vis HUD-panel
+
+ Zeige HUD Panel
+ [EN] Show HUD Panel
+ [EN] Show HUD Panel
+ [EN] Show HUD Panel
+ [EN] Show HUD Panel
+ [EN] Show HUD Panel
+
[EN] Show HUD Panel
+ [EN] Show HUD Panel
Show the World Events HUD overlay (F3 to toggle in-game)
Показати накладку HUD світових подій (F3 для перемикання в грі)
+ Vis HUD-overlayet for hændelser (F3 for at slå til/fra i spillet)
+
+ Zeige das Weltereignisse HUD (F3 zum Umschalten)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
+
[EN] Show the World Events HUD overlay (F3 to toggle in-game)
+ [EN] Show the World Events HUD overlay (F3 to toggle in-game)
HUD Scale
Масштаб HUD
+ HUD-skala
+
+ HUD-Skalierung
+ [EN] HUD Scale
+ [EN] HUD Scale
+ [EN] HUD Scale
+ [EN] HUD Scale
+ [EN] HUD Scale
+
[EN] HUD Scale
+ [EN] HUD Scale
Size of the World Events HUD panel
Розмір панелі HUD світових подій
+ Størrelse på HUD-panelet for hændelser
+
+ Größe des Weltereignisse HUD
+ [EN] Size of the World Events HUD panel
+ [EN] Size of the World Events HUD panel
+ [EN] Size of the World Events HUD panel
+ [EN] Size of the World Events HUD panel
+ [EN] Size of the World Events HUD panel
+
[EN] Size of the World Events HUD panel
+ [EN] Size of the World Events HUD panel
Economic Events
Економічні події
+ Økonomiske hændelser
+
+ Wirtschaftsereignisse
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+
[EN] Economic Events
+ [EN] Economic Events
Enable market and economic events
Увімкнути ринкові та економічні події
+ Slå markeds- og økonomiske hændelser til
+
+ Markt- und Wirtschaftsereignisse aktivieren
+ [EN] Enable market and economic events
+ [EN] Enable market and economic events
+ [EN] Enable market and economic events
+ [EN] Enable market and economic events
+ [EN] Enable market and economic events
+
[EN] Enable market and economic events
+ [EN] Enable market and economic events
Vehicle Events
Події з технікою
+ Køretøjshændelser
+
+ Fahrzeugereignisse
+ [EN] Vehicle Events
+ [EN] Vehicle Events
+ [EN] Vehicle Events
+ [EN] Vehicle Events
+ [EN] Vehicle Events
+
[EN] Vehicle Events
+ [EN] Vehicle Events
Enable vehicle events (speed, fuel, damage)
Увімкнути події з технікою (швидкість, паливо, пошкодження)
+ Aktivér køretøjshændelser (hastighed, brændstof, skader)
+
+ Aktiviere Fahrzeugereignisse (Geschwindigkeit, Verbrauch, Schaden)
+ [EN] Enable vehicle events (speed, fuel, damage)
+ [EN] Enable vehicle events (speed, fuel, damage)
+ [EN] Enable vehicle events (speed, fuel, damage)
+ [EN] Enable vehicle events (speed, fuel, damage)
+ [EN] Enable vehicle events (speed, fuel, damage)
+
[EN] Enable vehicle events (speed, fuel, damage)
+ [EN] Enable vehicle events (speed, fuel, damage)
Field Events
Події на полях
+ Markhændelser
+
+ Feldereignisse
+ [EN] Field Events
+ [EN] Field Events
+ [EN] Field Events
+ [EN] Field Events
+ [EN] Field Events
+
[EN] Field Events
+ [EN] Field Events
Enable crop and field events
Увімкнути події з культурами та полями
+ Aktivér afgrøde- og markhændelser
+
+ Aktiviere Ernte- und Feldereignisse
+ [EN] Enable crop and field events
+ [EN] Enable crop and field events
+ [EN] Enable crop and field events
+ [EN] Enable crop and field events
+ [EN] Enable crop and field events
+
[EN] Enable crop and field events
+ [EN] Enable crop and field events
Wildlife Events
Події з дикою природою
+ Dyrelivshændelser
+
+ Wildtierereignisse
+ [EN] Wildlife Events
+ [EN] Wildlife Events
+ [EN] Wildlife Events
+ [EN] Wildlife Events
+ [EN] Wildlife Events
+
[EN] Wildlife Events
+ [EN] Wildlife Events
Enable wildlife and animal events
Увімкнути події з дикою природою та тваринами
+ Aktivér hændelser med dyreliv og dyr
+
+ Wildtierereignisse aktivieren
+ [EN] Enable wildlife and animal events
+ [EN] Enable wildlife and animal events
+ [EN] Enable wildlife and animal events
+ [EN] Enable wildlife and animal events
+ [EN] Enable wildlife and animal events
+
[EN] Enable wildlife and animal events
+ [EN] Enable wildlife and animal events
Special Events
Особливі події
+ Særlige hændelser
+
+ Spezialereignisse
+ [EN] Special Events
+ [EN] Special Events
+ [EN] Special Events
+ [EN] Special Events
+ [EN] Special Events
+
[EN] Special Events
+ [EN] Special Events
Enable time, XP, and special events
Увімкнути події з часом, досвідом та особливі події
+ Aktivér tids-, XP- og Særlige hændelser
+
+ Zeit-, EP- und Spezialereignisse aktivieren
+ [EN] Enable time, XP, and special events
+ [EN] Enable time, XP, and special events
+ [EN] Enable time, XP, and special events
+ [EN] Enable time, XP, and special events
+ [EN] Enable time, XP, and special events
+
[EN] Enable time, XP, and special events
+ [EN] Enable time, XP, and special events
Enable Physics Override
Увімкнути налаштування фізики
+ Aktivér fysikoverstyring
+
+ Spielphysik überschreiben aktivieren
+ [EN] Enable Physics Override
+ [EN] Enable Physics Override
+ [EN] Enable Physics Override
+ [EN] Enable Physics Override
+ [EN] Enable Physics Override
+
[EN] Enable Physics Override
+ [EN] Enable Physics Override
Apply terrain-aware wheel grip and suspension
Застосувати зчеплення коліс і підвіску залежно від типу поверхні
+ Anvend terræntilpasset hjulgreb og affjedring
+
+ Aktiviere dynamischen Schlupf und Federung
+ [EN] Apply terrain-aware wheel grip and suspension
+ [EN] Apply terrain-aware wheel grip and suspension
+ [EN] Apply terrain-aware wheel grip and suspension
+ [EN] Apply terrain-aware wheel grip and suspension
+ [EN] Apply terrain-aware wheel grip and suspension
+
[EN] Apply terrain-aware wheel grip and suspension
+ [EN] Apply terrain-aware wheel grip and suspension
Wheel Grip
Зчеплення коліс
+ hjulgreb
+
+ Radschlupf
+ [EN] Wheel Grip
+ [EN] Wheel Grip
+ [EN] Wheel Grip
+ [EN] Wheel Grip
+ [EN] Wheel Grip
+
[EN] Wheel Grip
+ [EN] Wheel Grip
Scale terrain grip values (1.00 = default)
Масштаб зчеплення з поверхнею (1.00 = за замовчуванням)
+ Skaler terrænets grebsværdier (1,00 = standard)
+
+ Radschlupf einstellen (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
+
[EN] Scale terrain grip values (1.00 = default)
+ [EN] Scale terrain grip values (1.00 = default)
Suspension Stiffness
Жорсткість підвіски
+ Affjedringsstivhed
+
+ Federhärte
+ [EN] Suspension Stiffness
+ [EN] Suspension Stiffness
+ [EN] Suspension Stiffness
+ [EN] Suspension Stiffness
+ [EN] Suspension Stiffness
+
[EN] Suspension Stiffness
+ [EN] Suspension Stiffness
Scale suspension spring force (1.00 = default)
Масштаб сили пружини підвіски (1.00 = за замовчуванням)
+ Skaler affjedringens fjederkraft (1,00 = standard)
+
+ Federhärte einstellen (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
+
[EN] Scale suspension spring force (1.00 = default)
+ [EN] Scale suspension spring force (1.00 = default)
Show Physics Info
Показати інформацію про фізику
+ Vis fysikinfo
+
+ Info zur Physik zeigen
+ [EN] Show Physics Info
+ [EN] Show Physics Info
+ [EN] Show Physics Info
+ [EN] Show Physics Info
+ [EN] Show Physics Info
+
[EN] Show Physics Info
+ [EN] Show Physics Info
Log per-vehicle speed and grip data each frame
Записувати дані швидкості та зчеплення для кожного транспортного засобу щокадру
+ Log hastigheds- og grebsdata pr. køretøj i hver frame
+
+ Log pro Fahrzeug und Frame (Geschwindigkeit, Schlupf)
+ [EN] Log per-vehicle speed and grip data each frame
+ [EN] Log per-vehicle speed and grip data each frame
+ [EN] Log per-vehicle speed and grip data each frame
+ [EN] Log per-vehicle speed and grip data each frame
+ [EN] Log per-vehicle speed and grip data each frame
+
[EN] Log per-vehicle speed and grip data each frame
+ [EN] Log per-vehicle speed and grip data each frame
Debug Mode
Режим налагодження
+ Fejlfindingstilstand
+
+ Debugmodus
+ [EN] Debug Mode
+ [EN] Debug Mode
+ [EN] Debug Mode
+ [EN] Debug Mode
+ [EN] Debug Mode
+
[EN] Debug Mode
+ [EN] Debug Mode
Show verbose Random World Events debug output
Показувати детальні діагностичні дані випадкових світових подій
+ Vis detaljeret debugoutput for tilfældige hændelser
+
+ Zeige den Debug-Output der Weltereignisse
+ [EN] Show verbose Random World Events debug output
+ [EN] Show verbose Random World Events debug output
+ [EN] Show verbose Random World Events debug output
+ [EN] Show verbose Random World Events debug output
+ [EN] Show verbose Random World Events debug output
+
[EN] Show verbose Random World Events debug output
+ [EN] Show verbose Random World Events debug output
Toggle Random World Events HUD
Перемкнути HUD випадкових світових подій
+ Skift tilfældige hændelser HUD
+
+ Zufällige Weltereignisse HUD ein- und ausschalten
+ [EN] Toggle Random World Events HUD
+ [EN] Toggle Random World Events HUD
+ [EN] Toggle Random World Events HUD
+ [EN] Toggle Random World Events HUD
+ [EN] Toggle Random World Events HUD
+
[EN] Toggle Random World Events HUD
+ [EN] Toggle Random World Events HUD
Toggle Random World Events Settings
@@ -293,200 +698,641 @@
Abrir configurações de eventos aleatórios
Відкрити налаштування випадкових подій
Открыть настройки случайных событий
+ Slå indstillinger for Random World Events til/fra
Overview
Огляд
+ Oversigt
+
+ Übersicht
+ [EN] Overview
+ [EN] Overview
+ [EN] Overview
+ [EN] Overview
+ [EN] Overview
+
[EN] Overview
+ [EN] Overview
Event Categories
Категорії подій
+ Hændelseskategorier
+
+ Eventkategorien
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+ [EN] Event Categories
+
[EN] Event Categories
+ [EN] Event Categories
Settings
Налаштування
+ indstillinger
+
+ Einstellungen
+ [EN] Settings
+ [EN] Settings
+ [EN] Settings
+ [EN] Settings
+ [EN] Settings
+
[EN] Settings
+ [EN] Settings
Controls & Commands
Керування та команди
+ Styring & kommandoer
+
+ Tastaturbefehle
+ [EN] Controls & Commands
+ [EN] Controls & Commands
+ [EN] Controls & Commands
+ [EN] Controls & Commands
+ [EN] Controls & Commands
+
[EN] Controls & Commands
+ [EN] Controls & Commands
What is Random World Events?
Що таке випадкові світові події?
+ Hvad er Random World Events
+
+ Was sind zufällige Weltereignisse?
+ [EN] What is Random World Events?
+ [EN] What is Random World Events?
+ [EN] What is Random World Events?
+ [EN] What is Random World Events?
+ [EN] What is Random World Events?
+
[EN] What is Random World Events?
+ [EN] What is Random World Events?
Living World
Живий світ
+ Levende verden
+
+ Lebendige Welt
+ [EN] Living World
+ [EN] Living World
+ [EN] Living World
+ [EN] Living World
+ [EN] Living World
+
[EN] Living World
+ [EN] Living World
Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
Випадкові світові події привносять динамічні та непередбачувані події на вашу ферму. 53 унікальні події у п'яти категоріях запускаються автоматично під час гри, впливаючи на економіку, техніку, поля, дику природу та багато іншого. Жодне проходження не буде схожим на попереднє.
+ Random World Events bringer dynamiske og uforudsigelige hændelser til din gård. 53 unikke hændelser fordelt på fem kategorier udløses automatisk under spillet og påvirker din økonomi, dine køretøjer, marker, dyreliv og meget mere. Hver gennemspilning føles unik.
+
+ Zufällige Welteregnisse bringen dynamische, unvorhersagbare Ereignisse auf deine Farm. 53 einzigartige Ereignisse aus fünf Kategorien starten zufällig im Spiel und beeinflussen Wirtschaft, Fahrzeuge, Wildtiere und mehr. Kein Spieldurchlauf wird sich mehr gleich anfühlen.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+
[EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
+ [EN] Random World Events brings dynamic, unpredictable events to your farm. 53 unique events across five categories fire automatically during play, affecting your economy, vehicles, fields, wildlife, and more. No two playthroughs will feel the same.
What to Expect
Чого очікувати
+ Hvad kan du forvente
+
+ Was zu erwarten ist
+ [EN] What to Expect
+ [EN] What to Expect
+ [EN] What to Expect
+ [EN] What to Expect
+ [EN] What to Expect
+
[EN] What to Expect
+ [EN] What to Expect
Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
Події відображаються як сповіщення HUD і тривають налаштовуваний час. Деякі дають бонуси (підйоми на ринку, поповнення палива, підсилення врожаю), тоді як інші створюють труднощі (аварії, падіння цін, натовпи тварин). Таймер перерви запобігає надмірній кількості подій.
+ Hændelser vises som HUD-notifikationer og varer i et tidsrum, du selv kan konfigurere. Nogle giver bonusser (markedsboom, brændstofpåfyldning, afgrødebonusser), mens andre skaber udfordringer (ulykker, prisstyrt, paniske dyreflokke). En cooldown-timer sikrer, at hændelser ikke spammer spillet.
+
+ Die Ereignisse starten mit einer HUD-Benachrichtigung und dauern für eine einstellbare Zeit an. Einige geben Boni (z.B. Marktnachfrage, Betankungen oder Erntebuffs), andere sorgen für Schwierigkeiten (z.B. Unfälle, Preiseinbrüche, wilde Tierherden). Eingebaute Timer verhindern, dass zu viele Ereignisse starten.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+
[EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
+ [EN] Events appear as HUD notifications and last for a configurable duration. Some grant bonuses (market booms, fuel refills, crop buffs), while others impose challenges (accidents, price crashes, stampedes). A cooldown timer prevents event spam.
How Events Work
Як працюють події
+ Hvordan hændelser virker
+
+ Wie Ereignisse funktionieren
+ [EN] How Events Work
+ [EN] How Events Work
+ [EN] How Events Work
+ [EN] How Events Work
+ [EN] How Events Work
+
[EN] How Events Work
+ [EN] How Events Work
Trigger System
Система запуску
+ Hændelsesudløser
+
+ Auslösung
+ [EN] Trigger System
+ [EN] Trigger System
+ [EN] Trigger System
+ [EN] Trigger System
+ [EN] Trigger System
+
[EN] Trigger System
+ [EN] Trigger System
Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
При кожному ігровому тику є невелика ймовірність запуску події, яка контролюється параметром «Частота» (1–10). Коли подія запускається, з усіх увімкнених категорій вибирається випадкова відповідна подія. Одночасно може бути активна лише одна подія.
+ Ved hvert game-tick er der en lille sandsynlighed for, at en hændelse udløses, styret af indstillingen Hyppighed (1–10). Når en hændelse aktiveres, vælges en tilfældig tilgængelig hændelse fra alle aktiverede kategorier. Kun én hændelse kan være aktiv ad gangen.
+
+ Zu jedem Spielzeitpunkt ist es mit einer geringen Wahrscheinlichkeit möglich, ein Ereignis auszulösen - abhängig der eingestellten Frequenz (1-10). Wenn ein Ereignis ausgelöst wird, so wird ein zufälliges Ereignis aus allen aktiven Kategorien gewählt. Es kann nur ein Ereignis aktiv sein.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+
[EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
+ [EN] Each game tick there is a small probability of an event firing, controlled by the Frequency setting (1-10). When an event triggers, a random eligible event from all enabled categories is selected. Only one event can be active at a time.
Intensity & Cooldown
Інтенсивність та перерва
+ Intensitet & cooldown
+
+ Intensität & Cooldown
+ [EN] Intensity & Cooldown
+ [EN] Intensity & Cooldown
+ [EN] Intensity & Cooldown
+ [EN] Intensity & Cooldown
+ [EN] Intensity & Cooldown
+
[EN] Intensity & Cooldown
+ [EN] Intensity & Cooldown
Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
Інтенсивність (1–5) визначає силу ефектів — підйом ринку рівня 5 дає більший бонус, ніж рівень 1. Після кожної події має пройти час перерви (1–240 хвилин), перш ніж може статися наступна подія. Обидва параметри налаштовуються для кожного збереження.
+ Intensitet (1–5) skalerer styrken af effekterne — et markedsboom på niveau 5 giver en større bonus end niveau 1. Efter hver hændelse skal en cooldown-periode (1–240 minutter) passere, før den næste hændelse kan udløses. Begge indstillinger kan konfigureres separat for hvert savegame.
+
+ Intensität (1-5) skaliert die Effektstärke - ein Level 5 Marktboom gibt einen größeren Bonus als Level 1. Nach jedem Ereignis muss ein Cooldown abgewartet werden (1-240 Minuten), bevor ein neues Ereignis ausgelöst werden kann. Beide Einstellungen sind im Savegame konfigurierbar.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+
[EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
+ [EN] Intensity (1-5) scales the strength of effects — a level 5 market boom gives a bigger bonus than level 1. After each event, a cooldown period (1-240 minutes) must pass before the next event can fire. Both settings are configurable per savegame.
Economic Events
Економічні події
+ Økonomiske hændelser
+
+ Wirtschaftsereignisse
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+ [EN] Economic Events
+
[EN] Economic Events
+ [EN] Economic Events
Positive Events (11)
Позитивні події (11)
+ Positive hændelser (11)
+
+ 11 positive Ereignisse
+ [EN] Positive Events (11)
+ [EN] Positive Events (11)
+ [EN] Positive Events (11)
+ [EN] Positive Events (11)
+ [EN] Positive Events (11)
+
[EN] Positive Events (11)
+ [EN] Positive Events (11)
Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
Державні субсидії, підйоми на ринку, пожертви фермерів, повернення податків, страхові виплати, експортні можливості, знижки на насіння, знижки на добрива, знижки на паливо, знижки на обладнання та цінові бонуси (тимчасово підвищені ціни продажу). Ці події надають пряму готівку або тимчасові цінові бонуси.
+ Statslige tilskud, markedsboom, donationer fra landmænd, skatterefusioner, forsikringsudbetalinger, eksportmuligheder, rabatter på frø, rabatter på gødning, rabatter på brændstof, rabatter på udstyr samt bonusser fra prisfastsættelse (midlertidigt forhøjede salgspriser). Disse hændelser giver direkte kontanter eller midlertidige prisbonusser.
+
+ Staatliche Subventionen, Marktbooms, Spenden von Landwirten, Steuerrückerstattungen, Versicherungsleistungen, Exportmöglichkeiten, Saatgut-, Düngemittel-, Kraftstoff- und Geräterabatte sowie Preisbindungsprämien (vorübergehend erhöhte Verkaufspreise) können zu direkten Geldauszahlungen oder befristeten Preisboni führen.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+
[EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
+ [EN] Government subsidies, market booms, farmer donations, tax refunds, insurance payouts, export opportunities, seed discounts, fertilizer discounts, fuel discounts, equipment discounts, and price-fixing bonuses (temporary elevated sell prices). These events grant direct cash or temporary price bonuses.
Negative Events (4)
Негативні події (4)
+ Negative hændelser (4)
+
+ 4 negative Ereignisse
+ [EN] Negative Events (4)
+ [EN] Negative Events (4)
+ [EN] Negative Events (4)
+ [EN] Negative Events (4)
+ [EN] Negative Events (4)
+
[EN] Negative Events (4)
+ [EN] Negative Events (4)
Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
Обвали ринку (знижені ціни продажу), раптові витрати (миттєва втрата грошей), нарахування відсотків за кредитом (відсоток від наявних коштів) та економічні кризи (поєднання ринкових штрафів і поточних витрат за кредитом). Кризи високої інтенсивності накопичують обидва ефекти. Вимкніть категорію «Економіка», щоб відключити все це.
+ Markedsnedbrud (reducerede salgspriser), uforudsete udgifter (øjeblikkeligt pengetab), lånerenter (en procentdel af din nuværende saldo) og økonomiske kriser (kombineret markedstraf plus løbende låneomkostninger). Kriser med høj intensitet kombinerer begge effekter. Slå kategorien Økonomi fra for at deaktivere dem alle.
+
+ Markteinbrüche (sinkende Verkaufspreise), plötzliche Ausgaben (sofortiger Geldverlust), Kreditzinsen (Prozentsatz des aktuellen Geldbetrags) und Wirtschaftskrisen (Kombination aus Markteinbußen und laufenden Kreditkosten) verstärken diese Effekte. Schwere Krisen addieren beide Effekte. Deaktivieren der Kategtegorie Wirtschaft schalte all diese Effekte aus.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+
[EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
+ [EN] Market crashes (reduced sell prices), sudden expenses (immediate cash loss), loan interest charges (percentage of current money), and economic crises (combined market penalty plus ongoing loan costs). High-intensity crises stack both effects. Toggle the Economic category off to disable all of these.
Vehicle & Field Events
Події з технікою та полями
+ Køretøjs- & markhændelser
+
+ Fahrzeug- & Feldereignisse
+ [EN] Vehicle & Field Events
+ [EN] Vehicle & Field Events
+ [EN] Vehicle & Field Events
+ [EN] Vehicle & Field Events
+ [EN] Vehicle & Field Events
+
[EN] Vehicle & Field Events
+ [EN] Vehicle & Field Events
Vehicle Events (8)
Події з технікою (8)
+ Køretøjshændelser (8)
+
+ 8 Fahrzeugereignisse
+ [EN] Vehicle Events (8)
+ [EN] Vehicle Events (8)
+ [EN] Vehicle Events (8)
+ [EN] Vehicle Events (8)
+ [EN] Vehicle Events (8)
+
[EN] Vehicle Events (8)
+ [EN] Vehicle Events (8)
Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
Прискорення, безкоштовне поповнення палива, витік палива, дрібні аварії з рахунками за ремонт, повне чищення парку техніки, візуальні оновлення, проблеми з двигуном (знижена потужність) та екстрені рахунки за ремонт. Більшість подій з технікою стосуються транспортного засобу, яким ви керуєте.
+ Hastighedsboosts, gratis brændstofpåfyldninger, brændstoflækager, mindre ulykker med reparationsregninger, rengøring af hele køretøjsflåden, visuelle opgraderinger, motorproblemer (reduceret kraft) samt akutte reparationsregninger. De fleste køretøjshændelser påvirker det køretøj, du aktuelt styrer.
+
+ Höhere Geschwindigkeiten, kostenlose Tankfüllungen, Kraftstofflecks, kleinere Unfälle mit Reparaturkosten, Komplettreinigung der Flotte, kostenlose Lackierungen, Motorprobleme (Leistungsverlust) und Rechnungen für Notfallreparaturen. Die meisten Fahrzeugereignisse betreffen das aktuell gesteuerte Fahrzeug.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+
[EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
+ [EN] Speed boosts, free fuel refills, fuel leaks, minor accidents with repair bills, full fleet cleaning, visual upgrades, engine trouble (reduced power), and emergency repair bills. Most vehicle events target your currently controlled vehicle.
Field Events (10)
Події на полях (10)
+ Markhændelser (10)
+
+ 10 Feldereignisse
+ [EN] Field Events (10)
+ [EN] Field Events (10)
+ [EN] Field Events (10)
+ [EN] Field Events (10)
+ [EN] Field Events (10)
+
[EN] Field Events (10)
+ [EN] Field Events (10)
Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
Бонуси та штрафи до врожайності культур, подвоєна або вдвічі знижена ефективність добрив, зміни швидкості росту насіння, модифікатори кількості врожаю та зміни цін продажу з поля. Для подій на полях потрібне хоча б одне поле на карті.
+ Bonusser og straf på afgrødeudbytte, fordoblet eller halveret effektivitet af gødning, ændringer i frøenes væksthastighed, modifikatorer for høstmængde samt ændringer i markens salgspris. Markhændelser kræver, at der er mindst én mark på kortet for at kunne udløses.
+
+ Ernteertragsboni und -mali, verdoppelte oder halbierte Düngemittelwirkung, Änderungen der Wachstumsgeschwindigkeit, Modifikationen der Erntemenge und Änderungen der Feldverkaufspreise. Feldereignisse erfordern mindestens ein Feld auf der Karte, um ausgelöst zu werden.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+
[EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
+ [EN] Crop yield bonuses and penalties, doubled or halved fertilizer effectiveness, seed growth speed changes, harvest amount modifiers, and field sale price shifts. Field events require at least one field on the map to be eligible.
Special & Wildlife Events
Особливі події та події з дикою природою
+ Særlige & dyrelivshændelser
+
+ Spezial- & Wildtierereignisse
+ [EN] Special & Wildlife Events
+ [EN] Special & Wildlife Events
+ [EN] Special & Wildlife Events
+ [EN] Special & Wildlife Events
+ [EN] Special & Wildlife Events
+
[EN] Special & Wildlife Events
+ [EN] Special & Wildlife Events
Special Events (10)
Особливі події (10)
+ Særlige hændelser (10)
+
+ 10 Spezialereignisse
+ [EN] Special Events (10)
+ [EN] Special Events (10)
+ [EN] Special Events (10)
+ [EN] Special Events (10)
+ [EN] Special Events (10)
+
[EN] Special Events (10)
+ [EN] Special Events (10)
Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
Прискорення та уповільнення часу (впливає на масштаб ігрового часу), бонуси та штрафи до отримання досвіду, множники грошей, зміни міцності обладнання, кращі торгові ціни та міські фестивалі. Після закінчення часових подій відновлюється початковий масштаб часу.
+ Tidsacceleration og -opbremsning (påvirker spillets tidsskala), bonusser og straf på XP-optjening, pengemultiplikatorer, ændringer i udstyrets holdbarhed, bedre handelspriser samt byfestivaler. Tidsrelaterede hændelser gendanner den oprindelige tidsskala, når de slutter.
+
+ Zeitbeschleunigung und -verlangsamung (beeinflusst die Spielzeit), Boni und Mali beim EP-Gewinn, Geldmultiplikatoren, Änderungen der Ausrüstungshaltbarkeit, bessere Handelspreise und Stadtfeste. Zeitereignisse stellen nach ihrem Ende die ursprüngliche Zeit wieder her.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+
[EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
+ [EN] Time acceleration and slowdown (affects in-game time scale), XP gain bonuses and penalties, money multipliers, equipment durability changes, better trade prices, and town festivals. Time events restore the original time scale when they end.
Wildlife Events (10)
Події з дикою природою (10)
+ Dyrelivshændelser (10)
+
+ 10 Wildtierereignisse
+ [EN] Wildlife Events (10)
+ [EN] Wildlife Events (10)
+ [EN] Wildlife Events (10)
+ [EN] Wildlife Events (10)
+ [EN] Wildlife Events (10)
+
[EN] Wildlife Events (10)
+ [EN] Wildlife Events (10)
Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
Зграї птахів, корисні комахи, дикі натовпи тварин, сповіщення про хижаків, нашестя кролів, рої бджіл, бонуси сезону полювання, бонуси та штрафи до продуктів тваринництва, ветеринарні рахунки та спалахи хвороб. Увімкніть категорію «Дика природа», щоб переживати ці події.
+ Fugleflokke, nyttige insekter, vilde dyreflokke på flugt, rovdyrvarsler, kaninangreb, bisværme, bonusser i jagtsæsonen, bonusser og straf på husdyrprodukter, dyrlægeregninger samt sygdomsbekymringer. Aktivér kategorien Dyreliv for at opleve disse hændelser.
+
+ Vogelschwärme, nützliche Insekten, wilde Tierherden, Raubtierwarnungen, Kaninchenplagen, Bienenschwärme, Boni in der Jagdsaison, Boni und Mali bei der Viehprodukten, Tierarztkosten und Seuchenwarnungen. Diese Ereignisse sind nur aktiv, wenn die Einstellung Wildtiere aktiv ist.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+
[EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
+ [EN] Bird flocks, beneficial insects, wild stampedes, predator alerts, rabbit infestations, bee swarms, hunting season bonuses, livestock product bonuses and penalties, veterinary bills, and disease scares. Enable the Wildlife category to experience these.
Event Settings
Налаштування подій
+ Hændelsesindstillinger
+
+ Ereigniseinstellungen
+ [EN] Event Settings
+ [EN] Event Settings
+ [EN] Event Settings
+ [EN] Event Settings
+ [EN] Event Settings
+
[EN] Event Settings
+ [EN] Event Settings
Frequency (1-10)
Частота (1–10)
+ Frekvens (1–10)
+
+ Häufigkeit (1-10)
+ [EN] Frequency (1-10)
+ [EN] Frequency (1-10)
+ [EN] Frequency (1-10)
+ [EN] Frequency (1-10)
+ [EN] Frequency (1-10)
+
[EN] Frequency (1-10)
+ [EN] Frequency (1-10)
Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
Контролює, як часто відбуваються події. Вищі значення збільшують ймовірність запуску за кожен тік. Частота 10 означає, що події відбуваються майже в кожен період перерви, тоді як 1 робить їх дуже рідкісними. За замовчуванням встановлено 5 для збалансованого ігрового процесу.
+ Styrer, hvor ofte hændelser udløses. Højere værdier øger sandsynligheden for udløsning ved hvert tick. En hyppighed på 10 betyder, at hændelser udløses næsten ved hver cooldown-periode, mens 1 gør dem meget sjældne. Standardværdien er 5 for en afbalanceret oplevelse.
+
+ Steuert, wie oft Ereignisse eintreten. Höhere Werte steigern die Wahrscheinlichkeit. Eine Häufigkeit von 10 bedeutet, dass ein neues Ereignis nahezu immer nach dem Cooldown startet, während 1 Ereignisse sehr selten machen. Der Standard (5) ist für ein ausgewogenes Verhältnis.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+
[EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
+ [EN] Controls how often events fire. Higher values increase the per-tick trigger probability. A frequency of 10 means events fire nearly every cooldown period, while 1 makes them very rare. Default is 5 for a balanced experience.
Intensity (1-5) & Cooldown (1-240 min)
Інтенсивність (1–5) та перерва (1–240 хв)
+ Intensitet (1–5) & cooldown (1–240 min.)
+
+ Intensität (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
+
[EN] Intensity (1-5) & Cooldown (1-240 min)
+ [EN] Intensity (1-5) & Cooldown (1-240 min)
Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
Інтенсивність визначає масштаб ефектів подій — використовуйте нижчі значення для спокійного ігрового процесу, а вищі — для драматичних змін. Перерва встановлює мінімальний ігровий час між подіями. Збільшіть перерву для спокійнішого і менш частого ігрового процесу.
+ Intensitet skalerer styrken af hændelsernes effekter — brug lavere værdier for en mere rolig oplevelse og højere værdier for mere dramatiske udsving. Ventetid angiver det minimale antal minutter i spillet mellem hændelser. Øg ventetiden for en roligere oplevelse med færre hændelser.
+
+ Die Intensität skaliert die Stärke der Ereigniseffekte - kleinere Werte sorgen für ein harmonisches Erlebnis, größere Werte sorgen für stärkere Überraschungen. Der Cooldown setzt den Mindestwert in Ingame-Minuten zwischen den Ereignissen. Ein höherer Cooldown sorgt für ein ruhigeres Erlebnis mit weniger Ereignissen.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+
[EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
+ [EN] Intensity scales the magnitude of event effects — use lower values for a gentle experience and higher values for dramatic swings. Cooldown sets the minimum in-game minutes between events. Increase cooldown for a calmer, less frequent experience.
Physics Settings
Налаштування фізики
+ Fysiske indstillinger
+
+ Spielphysik-Einstellungen
+ [EN] Physics Settings
+ [EN] Physics Settings
+ [EN] Physics Settings
+ [EN] Physics Settings
+ [EN] Physics Settings
+
[EN] Physics Settings
+ [EN] Physics Settings
Wheel Grip & Suspension
Зчеплення коліс та підвіска
+ Hjulgreb & affjedring
+
+ Radschlupf & Federung
+ [EN] Wheel Grip & Suspension
+ [EN] Wheel Grip & Suspension
+ [EN] Wheel Grip & Suspension
+ [EN] Wheel Grip & Suspension
+ [EN] Wheel Grip & Suspension
+
[EN] Wheel Grip & Suspension
+ [EN] Wheel Grip & Suspension
The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
Система фізики застосовує зчеплення коліс залежно від типу поверхні для вашого транспортного засобу щокадру. Асфальт дає 110% зчеплення, бруд — 95%, поля — 85%, трава — 90%, сніг — 70%. Множник зчеплення коліс масштабує всі ці значення. Жорсткість підвіски множить силу пружини.
+ Fysiksystemet anvender terræntilpasset hjulfriktion på det køretøj, du styrer, i hver frame. Asfalt giver 110 % greb, jord 95 %, marker 85 %, græs 90 % og sne 70 %. Multiplikatoren for hjulgreb skalerer alle disse værdier. Affjedringsstivhed multiplicerer fjederkraften.
+
+ Das Physiksystem wendet in jedem Frame eine geländeabhängige Radreibung auf Ihr gesteuertes Fahrzeug an. Asphalt bietet 110 % Grip, Schotter 95 %, Wiesen 85 %, Gras 90 % und Schnee 70 %. Der Radgrip-Multiplikator skaliert all diese Werte. Die Federungssteifigkeit multipliziert die Federkraft.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+
[EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
+ [EN] The physics system applies terrain-aware wheel friction to your controlled vehicle every frame. Asphalt gives 110% grip, dirt 95%, fields 85%, grass 90%, and snow 70%. The Wheel Grip Multiplier scales all of these values. Suspension Stiffness multiplies spring force.
Debug & Physics Info
Налагодження та інформація про фізику
+ Fejlfinding & Fysisk info
+
+ Debug & Physikinfo
+ [EN] Debug & Physics Info
+ [EN] Debug & Physics Info
+ [EN] Debug & Physics Info
+ [EN] Debug & Physics Info
+ [EN] Debug & Physics Info
+
[EN] Debug & Physics Info
+ [EN] Debug & Physics Info
Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
Увімкніть «Показати інформацію про фізику», щоб записувати дані швидкості та множника для кожного транспортного засобу щокадру. Увімкніть режим налагодження для перегляду значень зчеплення кожного колеса. Це корисно для налаштування параметрів фізики, але може призвести до детального виводу в консоль під час звичайної гри.
+ Aktivér Vis fysikinfo for at logge hastigheds- og multiplikatordata pr. køretøj i hver frame. Aktivér Debugtilstand for grebsværdier pr. hjul. Disse er nyttige til finjustering af dine fysikindstillinger, men kan give meget detaljeret konsoloutput under normal spilbrug.
+
+ Aktivieren Sie die Physikinfo-Anzeige, um Geschwindigkeits- und Multiplikatordaten für jedes Fahrzeug in jedem Frame zu protokollieren. Aktivieren Sie den Debug-Modus für die Haftungswerte jedes einzelnen Rades. Diese Einstellungen sind nützlich, um die Physik-Einstellungen anzupassen, können aber während des normalen Spielverlaufs zu ausführlichen Konsolenausgaben führen.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+
[EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
+ [EN] Enable Show Physics Info to log per-vehicle speed and multiplier data each frame. Enable Debug Mode for per-wheel grip values. These are useful for tuning your physics settings but may produce verbose console output during normal play.
Controls & Console Commands
Керування та консольні команди
+ Styring & kommandoer
+
+ Tastatur- & Konsolenbefehle
+ [EN] Controls & Console Commands
+ [EN] Controls & Console Commands
+ [EN] Controls & Console Commands
+ [EN] Controls & Console Commands
+ [EN] Controls & Console Commands
+
[EN] Controls & Console Commands
+ [EN] Controls & Console Commands
Keyboard Shortcuts
Гарячі клавіші
+ Genvejstaster
+
+ Tastatur-Eingaben
+ [EN] Keyboard Shortcuts
+ [EN] Keyboard Shortcuts
+ [EN] Keyboard Shortcuts
+ [EN] Keyboard Shortcuts
+ [EN] Keyboard Shortcuts
+
[EN] Keyboard Shortcuts
+ [EN] Keyboard Shortcuts
F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
F3: Відкрити екран налаштувань випадкових світових подій. F9: Негайно примусово запустити випадкову подію (корисно для тестування). Ці прив'язки можна змінити в меню прив'язок клавіш гри в розділі «Випадкові світові події».
+ F3: Åbn indstillingsskærmen for Random World Events. F9: Tving straks en tilfældig hændelse til at udløses (nyttigt til test). Disse tastetildelinger kan ændres i spillets menu for tastetildelinger under sektionen Random World Events.
+
+ F3: Öffnet den Einstellungsbildschirm von zufällige Weltereignisse. F9: Sofort ein zufälliges Ereignis auslösen (nützlich zum Testen). Alle Belegungen können in den Spieleinstellungen unter dem Abschnitt zufällige Weltereignisse angepasst werden.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+
[EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
+ [EN] F3: Open the Random World Events settings screen. F9: Immediately force-trigger a random event (useful for testing). These bindings can be changed in the game's keybinding menu under the Random World Events section.
Console Commands
Консольні команди
+ Kommandoer
+
+ Konsolenbefehle
+ [EN] Console Commands
+ [EN] Console Commands
+ [EN] Console Commands
+ [EN] Console Commands
+ [EN] Console Commands
+
[EN] Console Commands
+ [EN] Console Commands
Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
Відкрийте консоль розробника та введіть: rwe (допомога), rweStatus (поточний стан), rweTest (примусовий запуск), rweEnd (зупинити активну подію), rweSettings (відкрити інтерфейс), rweDebug on|off (перемкнути детальне журналювання), rweList [категорія] (список усіх подій).
+ Åbn udviklerkonsollen og skriv: rwe (hjælp), rweStatus (nuværende status), rweTest (tving en hændelse til at udløses), rweEnd (stop aktiv hændelse), rweSettings (åbn GUI), rweDebug on|off (slå detaljeret logning til/fra), rweList [kategori] (vis alle hændelser).
+
+ In der geöffneten Entwicklerkonsole (Standard: ^): rwe (Hilfe), rweStatus (Aktueller Status), rweTest (sofortiges Ereignis), rweEnd (aktives Ereignis stoppen), rweSettings (Einstellungsbildschirm öffnen), rweDebug on|off (ausführliches Loggen (de)aktivieren), rweList [category] (Alle Ereignisse auflisten).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+
[EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
+ [EN] Open the developer console and type: rwe (help), rweStatus (current state), rweTest (force trigger), rweEnd (stop active event), rweSettings (open GUI), rweDebug on|off (toggle verbose logging), rweList [category] (list all events).
@@ -501,6 +1347,7 @@
HUD RWE exibido
HUD RWE показано
HUD RWE показан
+ RWE HUD aktiveret
RWE HUD hidden
@@ -513,6 +1360,7 @@
HUD RWE ocultado
HUD RWE приховано
HUD RWE скрыт
+ RWE HUD deaktiveret
WORLD EVENTS
@@ -525,6 +1373,7 @@
EVENTOS MUNDIAIS
СВІТОВІ ПОДІЇ
МИРОВЫЕ СОБЫТИЯ
+ HÆNDELSER
[ON]
@@ -537,6 +1386,7 @@
[LIG]
[УВК]
[ВКЛ]
+ [TÆNDT]
[OFF]
@@ -549,6 +1399,7 @@
[DES]
[ВИМ]
[ВЫКЛ]
+ [SlUKKET]
Ends in
@@ -561,6 +1412,7 @@
Termina em
Завершується через
Завершится через
+ Slutter om
No active event
@@ -573,6 +1425,7 @@
Nenhum evento ativo
Немає активної події
Нет активного события
+ Ingen aktive hændelser
Ready to trigger
@@ -585,6 +1438,7 @@
Pronto para acionar
Готово до запуску
Готов к запуску
+ Klar til aktivering
Next in %dm
@@ -597,6 +1451,7 @@
Próximo em %dm
Наступне через %dх
Следующее через %dм
+ Næste om %dm
Freq %d/10 | Intensity %d/5
@@ -609,6 +1464,7 @@
Freq. %d/10 | Intensidade %d/5
Частота %d/10 | Інтенс. %d/5
Частота %d/10 | Интенс. %d/5
+ Hyppighed %d/10 | Intensitet %d/5
Drag: move Corner: resize RMB: done
@@ -621,6 +1477,7 @@
Arrastar: mover Canto: redimensionar RMB: concluído
Перетяг: рух Кут: розмір ПКМ: готово
Перетащить: переместить Угол: размер ПКМ: готово
+ Træk: flyt Hjørne: ændr størrelse Højreklik: færdig
[F3]: toggle RMB: move/resize
@@ -633,6 +1490,7 @@
[F3]: alternar RMB: mover/redimensionar
[F3]: перемкнути ПКМ: рух/розмір
[F3]: переключить ПКМ: переместить/размер
+ [F3]: slå til/fra Højreklik: flyt/ændr størrelse