Card-Forge / Card-Forge/forge

Suggestion: Add dynamic difficulty scaling / handicap setting for adventure mode

Open
#11,807 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
2.7k
Forks
1.1k
Avg merge
1d 1h
Merged PRs (30d)
163

Description

After a while, the game becomes too easy. Searching for better cards loses its purpose, and long-term replayability suffers even when new quests are added.

To fix this in my own playthroughs, I created a custom workaround: enemies spawn with a permanent that tutors 3 random permanents from their deck and puts them onto the battlefield tapped during their first upkeep (which I applied across dungeon creatures using a PowerShell script). This added a great deal of fun and renewed my motivation to keep playing.

I suggest adding an official setting, such as a handicap slider from 0 to 10, that automatically adds that many random permanents to the enemy's board at the start or early phase of the match to dynamically scale late-game difficulty.

____
Here is the custom card I created. I would suggest refining the implementation to exile it instead of sacrificing it in order to prevent players from abusing recursion strategies:
Name:AI Difficulty Helper
ManaCost:no cost
Colors:white
Types:World Enchantment

T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDig1 | TriggerDescription$ At the beginning of your upkeep, put 3 random permanents from your library onto the battlefield tapped under your control. Sacrifice AI Difficulty Helper.

SVar:TrigDig1:DB$ DigUntil | Defined$ You | Valid$ Card.Artifact,Card.Creature,Card.Enchantment,Card.Land,Card.Planeswalker,Card.Battle,Card.Kindred | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPut1

SVar:DBPut1:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered | Tapped$ True | SubAbility$ DBCleanup1

SVar:DBCleanup1:DB$ Cleanup | ClearRemembered$ True | SubAbility$ TrigDig2

SVar:TrigDig2:DB$ DigUntil | Defined$ You | Valid$ Card.Artifact,Card.Creature,Card.Enchantment,Card.Land,Card.Planeswalker,Card.Battle,Card.Kindred | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPut2

SVar:DBPut2:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered | Tapped$ True | SubAbility$ DBCleanup2

SVar:DBCleanup2:DB$ Cleanup | ClearRemembered$ True | SubAbility$ TrigDig3

SVar:TrigDig3:DB$ DigUntil | Defined$ You | Valid$ Card.Artifact,Card.Creature,Card.Enchantment,Card.Land,Card.Planeswalker,Card.Battle,Card.Kindred | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPut3

SVar:DBPut3:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered | Tapped$ True | SubAbility$ DBCleanupFinal

SVar:DBCleanupFinal:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBSacrificeSelf

SVar:DBSacrificeSelf:DB$ Sacrifice | Defined$ Self

Oracle:At the beginning of your upkeep, put 3 random permanents from your library onto the battlefield tapped under your control. Sacrifice AI Difficulty Helper.

_______
Here is the Windows PowerShell script I run after every update to add this permanent to enemy decks at the start of the game. It would be even better if this could also be applied to world map encounters, though that seems to require engine-level changes (sorry for the french language):
# Chemin racine
$dossierMaps = "D:\forge\res\adventure\Realm of Legends\maps\map"

# Récupération récursive de tous les fichiers .tmx
$fichiersTmx = Get-ChildItem -Path $dossierMaps -Filter *.tmx -Recurse

# Définition de l'expression régulière
$recherche = '("startBattleWithCard":\s*\[\s*)'
$regex = [Regex] $recherche

# Réinsère le contenu capturé ($1) puis ajoute uniquement la nouvelle carte et sa virgule
$remplacement = '$1"AI Difficulty Helper", '

foreach ($fichier in $fichiersTmx) {
# Lecture brute en UTF-8 d'origine
$contenu = [System.IO.File]::ReadAllText($fichier.FullName, [System.Text.Encoding]::UTF8)

# Vérification stricte : contient la clé de combat et n'a PAS déjà l'aide
if ($contenu -match $recherche -and $contenu -notmatch "AI Difficulty Helper") {

# Sauvegarde de sécurité (.bak)
Copy-Item -Path $fichier.FullName -Destination "$($fichier.FullName).bak" -Force

# Remplacement chirurgical limité STRICTEMENT à 1 seule occurrence
$nouveauContenu = $regex.Replace($contenu, $remplacement, 1)

# Écriture forcée en UTF-8 STRICT sans BOM pour garantir la compatibilité Forge
$utf8SansBOM = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($fichier.FullName, $nouveauContenu, $utf8SansBOM)

Write-Host "Modifié (1ère occurrence seulement) : $($fichier.Name)" -ForegroundColor Green
} else {
Write-Host "Ignoré (Déjà fait ou sans startBattleWithCard) : $($fichier.Name)" -ForegroundColor Yellow
}
}

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the adventure map .tmx files and their existing startBattleWithCard entries, along with the provided PowerShell workaround. Then locate the engine entry point for adventure encounters and determine how a 0–10 handicap setting could affect enemy setup and world-map battles. Done means the setting is defined, applies the requested scaling consistently, and is covered by relevant tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, powershell
Domain
game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.