Skip to content

@lands.io/mod-sdk / DefaultConfig

Class: DefaultConfig

Default game configuration used as the base. Mods don't need to extend this - instead implement Partial and attach it to your Mod class via the static Config property.

Example

import { Mod, Config } from '@lands.io/mod-sdk';

class MyConfig implements Partial<Config> {
  // Override only what you need - rest falls back to DefaultConfig
  attackAmount(attacker, defender) {
    return attacker.troops() / 10;
  }
}

export default class MyMod extends Mod {
  static Config = MyConfig;
  // ... lifecycle hooks
}

Implements

Table of contents

Constructors

Properties

Methods

Constructors

constructor

new DefaultConfig(_gameConfig): DefaultConfig

Parameters

Name Type
_gameConfig GameConfig

Returns

DefaultConfig

Properties

_gameConfig

Protected _gameConfig: GameConfig

Methods

attackAmount

attackAmount(attacker, defender): number

Parameters

Name Type
attacker Player
defender Player | TerraNullius

Returns

number

Implementation of

Config.attackAmount


attackTilesPerTick

attackTilesPerTick(attackTroops, attacker, defender, numAdjacentTilesWithEnemy): number

Parameters

Name Type
attackTroops number
attacker Player
defender Player | TerraNullius
numAdjacentTilesWithEnemy number

Returns

number

Implementation of

Config.attackTilesPerTick


bots

bots(): number

Returns

number

Implementation of

Config.bots


difficultyModifier

difficultyModifier(difficulty): number

Parameters

Name Type
difficulty Difficulty

Returns

number


fakeHumans

fakeHumans(): number

Returns

number

Implementation of

Config.fakeHumans


gameConfig

gameConfig(): GameConfig

Returns

GameConfig

Implementation of

Config.gameConfig


goldAdditionRate

goldAdditionRate(player): number

Parameters

Name Type
player Player

Returns

number

Implementation of

Config.goldAdditionRate


infiniteGold

infiniteGold(): boolean

Returns

boolean

Implementation of

Config.infiniteGold


infiniteTroops

infiniteTroops(): boolean

Returns

boolean

Implementation of

Config.infiniteTroops


maxPopulation

maxPopulation(player): number

Parameters

Name Type
player Player

Returns

number

Implementation of

Config.maxPopulation


numBots

numBots(): number

Returns

number

Implementation of

Config.numBots


numSpawnPhaseTurns

numSpawnPhaseTurns(): number

Number of spawn-phase turns before regular gameplay starts. Set to 0 to skip extra spawn-phase turns.

Returns

number

Implementation of

Config.numSpawnPhaseTurns


percentageTilesOwnedToWin

percentageTilesOwnedToWin(): number

Returns

number

Implementation of

Config.percentageTilesOwnedToWin


populationIncreaseRate

populationIncreaseRate(player): number

Parameters

Name Type
player Player

Returns

number

Implementation of

Config.populationIncreaseRate


spawnImmunityDuration

spawnImmunityDuration(): number

Returns

number

Implementation of

Config.spawnImmunityDuration


startManpower

startManpower(player): number

Parameters

Name Type
player Player

Returns

number

Implementation of

Config.startManpower


troopAdjustmentRate

troopAdjustmentRate(player): number

Parameters

Name Type
player Player

Returns

number

Implementation of

Config.troopAdjustmentRate


unitInfo

unitInfo(type): UnitInfo

Parameters

Name Type
type UnitType

Returns

UnitInfo

Implementation of

Config.unitInfo


Source Code

View full implementation
/**
 * Default game configuration used as the base.
 * Mods don't need to extend this - instead implement Partial<Config>
 * and attach it to your Mod class via the static Config property.
 *
 * @example
 * ```typescript
 * import { Mod, Config } from '@lands.io/mod-sdk';
 *
 * class MyConfig implements Partial<Config> {
 *   // Override only what you need - rest falls back to DefaultConfig
 *   attackAmount(attacker, defender) {
 *     return attacker.troops() / 10;
 *   }
 * }
 *
 * export default class MyMod extends Mod {
 *   static Config = MyConfig;
 *   // ... lifecycle hooks
 * }
 * ```
 */
export class DefaultConfig implements Config {
  constructor(protected _gameConfig: GameConfig) {}

  // ============================================================
  // Game configuration (override to customize)
  // ============================================================

  gameConfig(): GameConfig {
    return this._gameConfig;
  }

  spawnImmunityDuration(): Tick {
    return 5 * 10;
  }

  numSpawnPhaseTurns(): number {
    return this._gameConfig.gameType === GameType.Singleplayer ? 70 : 150;
  }

  percentageTilesOwnedToWin(): number {
    return 80;
  }

  bots(): number {
    return this._gameConfig.bots;
  }

  numBots(): number {
    return this.bots();
  }

  fakeHumans(): number {
    return this._gameConfig.fakeHumans || 0;
  }

  infiniteGold(): boolean {
    return this._gameConfig.infiniteGold;
  }

  infiniteTroops(): boolean {
    return this._gameConfig.infiniteTroops;
  }

  // ============================================================
  // Player settings (override to customize)
  // ============================================================

  startManpower(player: Player): number {
    const maxPop = this.maxPopulation(player);
    const ratio = player.type() === PlayerType.Bot ? 0.5 : 0.75;
    return maxPop * ratio;
  }

  maxPopulation(player: Player): number {
    const maxPop = this.infiniteTroops()
      ? 1_000_000_000
      : Math.pow(player.numTilesOwned(), 0.6) * 100;
    return maxPop;
  }

  populationIncreaseRate(player: Player): number {
    const max = this.maxPopulation(player);
    const toAdd = max * 0.0007;
    return Math.min(player.population() + toAdd, max) - player.population();
  }

  goldAdditionRate(player: Player): number {
    return Math.sqrt(player.workers() * player.numTilesOwned()) / 200;
  }

  troopAdjustmentRate(player: Player): number {
    const maxDiff = this.maxPopulation(player) / 1000;
    const target = player.population() * player.targetTroopRatio();
    const diff = target - player.troops();
    if (Math.abs(diff) < maxDiff) {
      return diff;
    }
    const adjustment = maxDiff * Math.sign(diff);
    return adjustment < 0 ? adjustment * 5 : adjustment;
  }

  // ============================================================
  // Combat settings (override to customize)
  // ============================================================

  attackAmount(attacker: Player, defender: Player | TerraNullius): number {
    if (attacker.type() === PlayerType.Bot) {
      return attacker.troops() / 20;
    }
    return attacker.troops() / 5;
  }

  attackTilesPerTick(
    attackTroops: number,
    attacker: Player,
    defender: Player | TerraNullius,
    numAdjacentTilesWithEnemy: number,
  ): number {
    if ('isPlayer' in defender && defender.isPlayer()) {
      return (
        within(((5 * attackTroops) / defender.troops()) * 2, 0.01, 0.5) *
        numAdjacentTilesWithEnemy *
        3
      );
    }
    const troopFactor = Math.min(3, Math.max(1, Math.sqrt(attackTroops / 500) * 3));
    return numAdjacentTilesWithEnemy * 2 * troopFactor;
  }

  // ============================================================
  // Unit costs (override to customize)
  // ============================================================

  unitInfo(type: UnitType): UnitInfo {
    // Default costs - override for custom pricing
    const defaultInfo: UnitInfo = {
      cost: () => 100_000,
      territoryBound: true,
    };
    return defaultInfo;
  }

  // ============================================================
  // Difficulty settings
  // ============================================================

  difficultyModifier(difficulty: Difficulty): number {
    switch (difficulty) {
      case Difficulty.Easy:
        return 1;
      case Difficulty.Medium:
        return 3;
      case Difficulty.Hard:
        return 9;
      case Difficulty.Impossible:
        return 18;
    }
  }
}