sim/config.rn

260 lines
8.6 KiB
Plaintext
Raw Permalink Normal View History

// Simulation script: `pub const` items are defaults and tuning constants,
// `pub fn` items are entity behaviours. Every constant below is required.
// World
pub const WIDTH = 192;
pub const HEIGHT = 128;
// Calendar
pub const TICKS_PER_DAY = 1800;
pub const DAYS_PER_WEEK = 7;
pub const WEEKS_PER_MONTH = 4;
pub const MONTHS_PER_YEAR = 12;
// Life stages: days spent in each stage; fertile stages can have children
pub const TODDLER = #{ min_days: 2, max_days: 4, fertile: false };
pub const CHILD = #{ min_days: 4, max_days: 8, fertile: false };
2026-10-11 19:37:12 +00:00
pub const TEEN = #{ min_days: 4, max_days: 8, fertile: true };
pub const YOUNG_ADULT = #{ min_days: 6, max_days: 12, fertile: true };
pub const ADULT = #{ min_days: 20, max_days: 40, fertile: true };
2026-10-11 19:37:12 +00:00
pub const OLDER_ADULT = #{ min_days: 10, max_days: 20, fertile: true };
pub const ELDERLY = #{ min_days: 4, max_days: 10, fertile: false };
// Initial world
pub const INITIAL_POPULATION = 180;
pub const INITIAL_YOUNG_ADULTS = 60;
pub const INITIAL_RABBITS = 1200;
pub const INITIAL_WOLVES = 80;
pub const INITIAL_FOOD = 1200;
pub const INITIAL_PERSON_HUNGER = 10.0;
pub const INITIAL_ANIMAL_ENERGY = 70.0;
pub const ANIMAL_ENERGY_DEATH_THRESHOLD = 0.0;
pub const STARTING_TICK_FRACTION = 4;
// Population and housing
pub const POPULATION_CAPACITY = 30;
pub const HOUSE_CAPACITY = 3;
pub const MAX_HOUSES = 20;
// Daylight
pub const DAYLIGHT_NIGHT_THRESHOLD = 0.2;
pub const DAYLIGHT_BASE = 0.5;
pub const DAYLIGHT_AMPLITUDE = 0.8;
// Movement and update cadence
pub const HOME_RADIUS = 1;
pub const ATTACK_RANGE = 1;
pub const ENTITY_UPDATE_INTERVAL = 2;
// Hunger
pub const HUNGER_NIGHT_AT_HOME = 0.01;
pub const HUNGER_OTHER = 0.02;
pub const HUNGER_EAT_HOME_THRESHOLD = 40.0;
pub const HUNGER_EAT_CARRIED_THRESHOLD = 50.0;
pub const HUNGER_RETURN_THRESHOLD = 40.0;
pub const HUNGER_STARVATION_THRESHOLD = 100.0;
pub const HUNGER_MEAL_REDUCTION = 25.0;
pub const FOOD_PER_MEAL = 1;
// People: gathering and hunting
pub const RESOURCE_SEARCH_RADIUS = 25;
pub const PERSON_HUNT_SUCCESS_CHANCE = 0.5;
pub const PERSON_HUNT_FOOD_YIELD = 3;
pub const PERSON_GATHER_YIELD = 1;
pub const PERSON_TOOLED_GATHER_YIELD = 2;
// Partnerships and births
pub const PARTNERSHIP_DISTANCE = 12;
pub const BIRTH_FOOD_THRESHOLD = 10;
pub const BIRTH_FOOD_COST = 6;
// Construction
pub const TOOL_WOOD_COST = 3;
pub const TOOL_STONE_COST = 1;
pub const HOUSE_WOOD_COST = 12;
pub const HOUSE_STONE_COST = 4;
pub const HOUSE_PLACEMENT_RADIUS = 6;
// Resources
pub const RESOURCE_REGROW_ATTEMPTS = 20;
pub const INITIAL_TREE_CHANCE = 0.6;
pub const INITIAL_TREE_AMOUNT = 5;
pub const INITIAL_BERRY_CHANCE = 0.04;
pub const INITIAL_BERRY_AMOUNT = 4;
pub const INITIAL_STONE_CHANCE = 0.15;
pub const INITIAL_STONE_AMOUNT = 6;
pub const TREE_REGROW_CHANCE = 0.02;
pub const TREE_REGROW_AMOUNT = 5;
pub const BERRY_REGROW_CHANCE = 0.02;
pub const BERRY_REGROW_AMOUNT = 4;
pub const STONE_REGROW_CHANCE = 0.004;
pub const STONE_REGROW_AMOUNT = 6;
// Animal spawning
pub const ANIMAL_POPULATION_INTERVAL = 50;
pub const RABBIT_SPAWN_CAP = 30;
pub const WOLF_SPAWN_CAP = 4;
pub const WOLF_SPAWN_RABBIT_THRESHOLD = 80;
pub const WOLF_MIN_HOME_DISTANCE = 15;
// Rabbits
pub const RABBIT_ENERGY_DRAIN = 0.05;
pub const RABBIT_ENERGY_REGEN = 0.2;
pub const RABBIT_ENERGY_MAX = 100.0;
pub const RABBIT_WOLF_DETECTION_RANGE = 4;
pub const RABBIT_BREED_ENERGY = 80.0;
pub const RABBIT_MAX_POPULATION = 300;
pub const RABBIT_BREED_CHANCE = 0.01;
pub const RABBIT_BREED_ENERGY_COST = 30.0;
pub const RABBIT_NEWBORN_ENERGY = 50.0;
// Wolves
pub const WOLF_ENERGY_DRAIN = 0.15;
pub const WOLF_PREY_RANGE = 10;
pub const WOLF_HUNT_SUCCESS_CHANCE = 0.4;
pub const WOLF_HUNT_ENERGY_GAIN = 50.0;
pub const WOLF_ENERGY_MAX = 100.0;
pub const WOLF_BREED_ENERGY = 90.0;
pub const WOLF_MAX_POPULATION = 24;
pub const WOLF_BREED_CHANCE = 0.02;
pub const WOLF_BREED_ENERGY_COST = 40.0;
pub const WOLF_NEWBORN_ENERGY = 50.0;
// Terrain generation
pub const TERRAIN_NOISE_OCTAVES = 4;
pub const TERRAIN_NOISE_SCALE = 16.0;
pub const TERRAIN_EDGE_HEIGHT = 0.25;
pub const TERRAIN_EDGE_FALLOFF = 0.55;
pub const TERRAIN_EDGE_DISTANCE_CAP = 1.5;
pub const TERRAIN_MOISTURE_OFFSET = 500.0;
pub const TERRAIN_MOISTURE_SEED_OFFSET = 99;
pub const TERRAIN_DEEP_WATER_THRESHOLD = 0.28;
pub const TERRAIN_WATER_THRESHOLD = 0.36;
pub const TERRAIN_SAND_THRESHOLD = 0.41;
pub const TERRAIN_FOREST_GRASS_THRESHOLD = 0.68;
pub const TERRAIN_HILLS_THRESHOLD = 0.78;
pub const TERRAIN_FOREST_MOISTURE_THRESHOLD = 0.52;
// Misc
pub const RANDOM_LAND_ATTEMPTS = 50;
pub const LOG_ENTRY_LIMIT = 8;
pub const WANDER_ATTEMPTS = 4;
pub const WANDER_RADIUS = 1;
// UI edit limits
pub const MANUAL_SPAWN_LIMIT = 25;
pub const MAX_SIMULATION_SPEED = 8;
pub const MAX_STOCK_EDIT = 9999;
pub const MAX_PERSON_INVENTORY_EDIT = 99;
pub const MAX_HUNGER_EDIT = 99;
pub const MAX_ANIMAL_ENERGY_EDIT = 100.0;
pub const MAX_RESOURCE_EDIT = 50;
// Economy: the share of each day people work, and how much they carry
pub const WORK_START = 0.3;
pub const WORK_END = 0.65;
pub const CARRY_CAPACITY = 8;
pub const CART_CAPACITY = 24;
pub const CART_DURABILITY = 3000;
pub const CART_WOOD_COST = 8;
// Economy: money, households and employment
pub const INITIAL_PERSON_COINS = 20;
pub const INITIAL_WORKPLACE_COINS = 150;
pub const INITIAL_MARKET_COINS = 600;
pub const QUIT_AFTER_UNPAID_DAYS = 3;
// Workers top up the village food stock to this many units per resident.
pub const HOUSEHOLD_FOOD_TARGET = 25;
pub const HOUSEHOLD_COIN_RESERVE = 10;
pub const CART_PURCHASE_COINS = 80;
// Economy: work sites, farming and trade
pub const WORK_RADIUS = 8;
pub const FIELD_RADIUS = 2;
pub const CROP_RIPE = 4;
pub const CROP_YIELD = 4;
pub const CRAFT_BUDGET = 40;
pub const MERCHANT_ESCROW = 60;
pub const HAGGLE_ROUNDS = 4;
// Goods: base price, and the stock at which a market charges the base price
pub const PRICE_FOOD = #{ price: 4, target: 60 };
pub const PRICE_WOOD = #{ price: 2, target: 40 };
pub const PRICE_STONE = #{ price: 3, target: 30 };
pub const PRICE_TOOLS = #{ price: 14, target: 8 };
pub const PRICE_CARTS = #{ price: 40, target: 2 };
// Trades: sites per shard, workers per site and the wage per shift.
// TRADE_MERCHANT.count is the number of markets per shard (0 disables the economy).
pub const TRADE_FARM = #{ count: 2, workers: 3, wage: 6 };
pub const TRADE_WOODCUTTER = #{ count: 1, workers: 3, wage: 5 };
pub const TRADE_QUARRY = #{ count: 1, workers: 2, wage: 5 };
pub const TRADE_HUNTER = #{ count: 1, workers: 2, wage: 5 };
pub const TRADE_TOOLMAKER = #{ count: 1, workers: 1, wage: 7 };
pub const TRADE_CARTWRIGHT = #{ count: 1, workers: 1, wage: 7 };
pub const TRADE_MERCHANT = #{ count: 1, workers: 2, wage: 8 };
// Behaviour tuning (used only by the behaviour functions below)
pub const HUNGER_SCRIPT_THRESHOLD = 50.0;
pub const PERSON_CARRY_LIMIT = 6;
pub const PERSON_FOOD_STOCK_THRESHOLD = 12;
pub const PERSON_HUNT_RABBIT_CHANCE = 0.3;
pub const PERSON_WOOD_STONE_RATIO = 2;
pub const PERSON_WOOD_BUFFER = 8;
pub const RABBIT_BEHAVIOR_FLEE_CHANCE = 0.8;
pub const RABBIT_BEHAVIOR_WANDER_CHANCE = 0.5;
// Behaviours. Each function receives what the entity senses and returns the
// name of an action; the Rust side carries it out.
// person: work | rest | sleep | go_home | eat | haul | hunt | forage | chop | mine | wander
pub fn person(c) {
if c.on_trip {
return "work";
}
if c.night {
return if c.at_home { "sleep" } else { "go_home" };
}
if c.hunger > HUNGER_SCRIPT_THRESHOLD && c.carried_food == 0 && c.stock_food > 0 {
return "eat";
}
if c.employed && (c.on_shift || (c.work_time && !c.shift_done)) {
return "work";
}
if c.employed && c.shift_done {
return if c.at_home { "rest" } else { "go_home" };
}
if c.carry >= PERSON_CARRY_LIMIT {
return "haul";
}
if c.stock_food < PERSON_FOOD_STOCK_THRESHOLD || c.hunger > HUNGER_SCRIPT_THRESHOLD {
if c.rabbit_near && (!c.berry_near || c.roll < PERSON_HUNT_RABBIT_CHANCE) {
return "hunt";
}
if c.berry_near {
return "forage";
}
}
if c.stock_wood <= c.stock_stone * PERSON_WOOD_STONE_RATIO + PERSON_WOOD_BUFFER {
if c.tree_near { "chop" } else if c.stone_near { "mine" } else { "wander" }
} else {
if c.stone_near { "mine" } else if c.tree_near { "chop" } else { "wander" }
}
}
// rabbit: flee | wander | stay
pub fn rabbit(c) {
if c.wolf_near {
if c.roll < RABBIT_BEHAVIOR_FLEE_CHANCE { "flee" } else { "stay" }
} else if c.roll < RABBIT_BEHAVIOR_WANDER_CHANCE {
"wander"
} else {
"stay"
}
}
// wolf: hunt | wander
pub fn wolf(c) {
if c.prey_near { "hunt" } else { "wander" }
}