veritaminal
Version:
An AI-powered border control simulation game inspired by Papers, Please. Make critical decisions as a border agent while navigating corruption, trust, and moral dilemmas across multiple story-driven scenarios.
288 lines (262 loc) • 11.6 kB
JavaScript
/**
* Settings module for Veritaminal
* Handles border settings, game configurations, and contextual information
* for different game scenarios.
*/
import chalk from 'chalk'; // Using chalk directly for any potential inline styling needed
import path from 'path';
import { fileURLToPath } from 'url';
// Helper to get __dirname in ES Modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Predefined border settings for the game
const BORDER_SETTINGS = [
{
"id": "eastokan_westoria",
"name": "Eastokan-Westoria Border",
"situation": "Tense relations due to recent trade disputes. Increased scrutiny on business travelers.",
"description": "The border between the industrial nation of Eastokan and the agricultural country of Westoria. Recent trade disputes have heightened tensions.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Travelers must have both first and last names",
"Business travelers require a trade visa stamp"
],
"common_issues": [
"Forged business credentials",
"Expired permits",
"Identity mismatches in documentation"
]
},
{
"id": "northland_southoria",
"name": "Northland-Southoria Border",
"situation": "Post-conflict reconciliation with humanitarian crisis. Focus on refugee documentation.",
"description": "Following the peace treaty ending the 5-year conflict, this border handles many refugees and humanitarian workers.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Humanitarian workers need special H-class authorization",
"Refugee documents must include origin verification"
],
"common_issues": [
"Missing refugee documentation",
"Impersonation of humanitarian workers",
"Forged origin documentation"
]
},
{
"id": "oceania_continent",
"name": "Oceania-Continent Ferry Checkpoint",
"situation": "Tourism boom with increasing smuggling concerns. Focus on contraband detection.",
"description": "This busy checkpoint manages traffic between the island nation of Oceania and the mainland Continent. Tourism is booming, but smuggling is on the rise.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Tourist visas require verification stamps",
"Commercial transport requires cargo manifests"
],
"common_issues": [
"Overstayed tourist visas",
"Undeclared commercial activity",
"Falsified transport documentation"
]
},
{
"id": "alpinia_metropol",
"name": "Alpinia-Metropol Mountain Pass",
"situation": "High-altitude border crossing with strict environmental regulations. Monitoring scientific expeditions and rare mineral trafficking.",
"description": "The challenging mountain pass between the alpine nation of Alpinia and the city-state of Metropol. Environmental protection and scientific research permits are heavily regulated.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Scientific personnel require research authorization",
"Environmental impact assessments mandatory for expeditions"
],
"common_issues": [
"Forged research credentials",
"Undeclared scientific equipment",
"Illegal rare mineral smuggling"
]
},
{
"id": "desert_emirates_republic",
"name": "Desert Emirates-Republic Checkpoint",
"situation": "Oil-rich region with complex diplomatic relations. Focus on energy sector workers and diplomatic immunity abuse.",
"description": "The bustling border between the wealthy Desert Emirates and the industrial Republic. Energy trade dominates, but diplomatic tensions create security challenges.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Energy sector workers need specialized clearance",
"Diplomatic personnel require verified immunity status"
],
"common_issues": [
"Abuse of diplomatic immunity",
"Forged energy sector credentials",
"Unauthorized technology transfers"
]
},
{
"id": "frozen_archipelago_mainland",
"name": "Frozen Archipelago-Mainland Ice Bridge",
"situation": "Seasonal ice bridge crossing with indigenous rights concerns. Monitoring cultural artifacts and traditional fishing permits.",
"description": "The temporary ice bridge connecting the indigenous territories of Frozen Archipelago to the Mainland. Cultural preservation and traditional rights create unique documentation challenges.",
"document_requirements": [
"Permit must start with 'P' followed by 4 digits",
"Indigenous travelers need tribal verification",
"Cultural artifacts require heritage documentation"
],
"common_issues": [
"Forged tribal credentials",
"Illegal cultural artifact trafficking",
"Unauthorized fishing in traditional waters"
]
}
];
class SettingsManager {
/**
* Manages game settings and border configurations.
*/
constructor() {
/** @type {object|null} */
this.currentSetting = null;
this.availableSettings = BORDER_SETTINGS;
/** @type {string[]} */
this.customRules = [];
// Game configuration settings
this.gameConfig = {
totalDays: 10, // Total days to complete the assignment
travelersPerDay: 5, // Number of travelers to process per day
allowCustomization: true // Whether players can modify these settings
};
// Note: UI instance removed here; display logic belongs in ui.js
}
/**
* Get all available border settings.
* @returns {object[]} List of available border settings.
*/
getAvailableSettings() {
return this.availableSettings;
}
/**
* Select a border setting by ID.
* @param {string} settingId - The ID of the setting to select.
* @returns {object} The selected setting.
*/
selectSetting(settingId) {
const setting = this.availableSettings.find(s => s.id === settingId);
if (setting) {
this.currentSetting = setting;
this.customRules = []; // Reset custom rules when changing setting
return setting;
}
// If ID not found, default to the first setting
console.warn(chalk.yellow(`Setting ID '${settingId}' not found. Using default.`));
this.currentSetting = this.availableSettings[0];
this.customRules = [];
return this.currentSetting;
}
/**
* Get the current border setting.
* @returns {object} The current setting.
*/
getCurrentSetting() {
if (!this.currentSetting) {
// If no setting is selected, use the first one as default
this.currentSetting = this.availableSettings[0];
this.customRules = [];
}
return this.currentSetting;
}
/**
* Add a custom rule to the current setting.
* @param {string} ruleDescription - Description of the rule.
* @returns {boolean} True if the rule was added successfully.
*/
addCustomRule(ruleDescription) {
// Ensure a setting is selected
this.getCurrentSetting();
if (!this.customRules.includes(ruleDescription)) {
this.customRules.push(ruleDescription);
return true;
}
return false;
}
/**
* Get all rules for the current setting.
* @returns {string[]} Combined list of default and custom rules.
*/
getAllRules() {
const setting = this.getCurrentSetting();
return [...setting.document_requirements, ...this.customRules];
}
/**
* Get a formatted context string for the current setting.
* @returns {string} A formatted context string.
*/
getSettingContext() {
const setting = this.getCurrentSetting();
let context = [];
context.push(`BORDER: ${setting.name}`);
context.push(`SITUATION: ${setting.situation}`);
context.push("\nDOCUMENT REQUIREMENTS:");
setting.document_requirements.forEach(req => context.push(`- ${req}`));
if (this.customRules.length > 0) {
context.push("\nADDITIONAL RULES:");
this.customRules.forEach(rule => context.push(`- ${rule}`));
}
return context.join("\n");
}
/**
* Get current game configuration settings.
* @returns {object} Current game configuration.
*/
getGameConfig() {
return { ...this.gameConfig }; // Return a copy to prevent external modification
}
/**
* Update game configuration settings.
* @param {object} newConfig - New configuration values { totalDays?, travelersPerDay? }.
* @returns {boolean} True if configuration was updated successfully.
*/
updateGameConfig(newConfig) {
if (!this.gameConfig.allowCustomization) {
console.warn(chalk.yellow("Game configuration customization is disabled."));
return false;
}
let updated = false;
if (newConfig.totalDays !== undefined) {
const days = parseInt(newConfig.totalDays);
if (days >= 1 && days <= 30) { // Reasonable limits
this.gameConfig.totalDays = days;
updated = true;
} else {
console.warn(chalk.yellow(`Invalid totalDays value: ${newConfig.totalDays}. Must be 1-30.`));
}
}
if (newConfig.travelersPerDay !== undefined) {
const travelers = parseInt(newConfig.travelersPerDay);
if (travelers >= 1 && travelers <= 20) { // Reasonable limits
this.gameConfig.travelersPerDay = travelers;
updated = true;
} else {
console.warn(chalk.yellow(`Invalid travelersPerDay value: ${newConfig.travelersPerDay}. Must be 1-20.`));
}
}
if (updated) {
console.log(chalk.green(`Game configuration updated: ${this.gameConfig.totalDays} days, ${this.gameConfig.travelersPerDay} travelers per day.`));
}
return updated;
}
/**
* Reset game configuration to defaults.
*/
resetGameConfig() {
this.gameConfig.totalDays = 10;
this.gameConfig.travelersPerDay = 5;
console.log(chalk.blue("Game configuration reset to defaults."));
}
/**
* Get a formatted string of current game configuration for display.
* @returns {string} Formatted configuration info.
*/
getGameConfigSummary() {
return `Assignment Duration: ${this.gameConfig.totalDays} days\nTravelers per Day: ${this.gameConfig.travelersPerDay} people`;
}
}
export { SettingsManager };