The Countdown Begins!

Here’s some c++ I was working on, if you want to use it to run a command, go ahead:

C++
//---------------------------------
// FUNCTION HELP_F

// declare a function called "help_f" (short for (help_f)unction)
satellite_space::satellite_system help_f(satellite_space::satellite_system satellite)
{
  // set the global system state so all components know what state we are in,
	satellite.call_set_global_system_state(50); // 50 for printer, or help
	
	// this is a syntax I wrote to define a way to declare that it's just, "satellite input"
	std::string local_user_input = "{!satellite_input}";
	
	// this is obvious a vector of strings called input_library
	std::vector<std::string> input_library;
	
	// same thing as before
	std::vector<std::string> quit_words;
	
	// how to insert objects into a vector,
	quit_words.push_back("quit");
	quit_words.push_back("exit");
	quit_words.push_back("leave");
	quit_words.push_back("shutdown");
	quit_words.push_back("terminate");
	quit_words.push_back("abort");
	
	// just some declarations
	bool collect_input = true;
	signed long long int current_quit_word = 0;
	signed long long int size_of_quit_words = quit_words.size();
	
	// another vector of strings declaration
	std::vector<std::string> word_list;
	
	// more how to append an item to a vector;
	word_list.push_back("help");
	word_list.push_back("commands");
	word_list.push_back("h");
	word_list.push_back("cmd");
	word_list.push_back("command");
	word_list.push_back("cmds");
	
	// some declarations
	signed long long int size_of_word_list = word_list.size();
	
	signed long long int current_word = 0;
	
	// while we want to collect_input, run this block of code
	while (collect_input == true)
	{
	  // if the user comes from the beginning, we must append {!satellite_input} to the input_library
		input_library.push_back(local_user_input);
		
	  // this is where it gets tricky, from object satellite, object orbital_printer's call_return_local_user_input() function
		local_user_input = satellite.orbital_printer->call_return_local_user_input();
		
		// while the current quit word is lower than the total quit words, the size of quit words,
		while (current_quit_word < size_of_quit_words)
		{
		  // if the substring 0 to quit_words[current_quit_word].size() is quit_words[current_quit_word]
			if (local_user_input.substr(0, quit_words[current_quit_word].size()) == quit_words[current_quit_word])
			{
			  // don't collect_input, we want to quit!
				collect_input = false;
			
			  // from the object satellite, call_system_shutdown function
				satellite.call_system_shutdown();
			}
		}
		
		// if collect_input is still true, do this
		if (collect_input == true)
		{
		  // if this substring is "satellite", do this
			if (local_user_input.substr(0, 8) != "satellite")
			{
			  // from object satellite call activate error_state function and pass it the argument "0"
				satellite.call_activate_error_state(0); // 0 for no satellite
				
				// display the console prompt
				satellite.orbital_printer->call_display_prompt();
				
				// display text in front of the console prompt,
				std::cout << "did you forget to include the word \"satellite\" at the beginning of your input? For example, satellite.help(\"commands\") would bring up the help file for commands, while help(\"commands\") would pass the argument \"commands\" to the user defined function \"help()\".";
			}
			
			// if the error_state is false, do this
			if (satellite.call_return_error_state() == false)
			{
			  // just displaying a string
				std::cout << "input begins with the word \"satellite\" so we can continue\n";
				
				// if the size of locaL_user_input equals 8
				if (local_user_input.size() == 8)
				{
				  // from object satellite, call_set_error_state and pass it two arguments, the number 1 and the string below
					satellite.call_set_error_state(1, "input contains just the word \"satellite\" and nothing else, see also \"satellite.help(\"commands\")\" or just \"satellite.help()\"");
					
					// displays the prompt for output,
					satellite.orbital_printer->call_display_prompt();
					
					// display this string
					std::cout << "your input contained only the word \"satellite\" which is invalid input, because you would need to include another word like \"help\" as in \"satellite.help()\" see also satellite.help()\n";
				}
				
				// if the error_state is false, do this
				if (satellite.call_return_error_state() == false)
				{
				  // if the debug_state is true
					if (satellite.call_return_debug_state() == true)
					{
					  // display this string
						std::cout << "input contains the word \"satellite\" and doesn\'t end in 8 characters, so we can continue\n";
						
						// if verbose debug mode is on, do this
						if (satellite.call_return_verbose_debug_mode() == true)
						{
						  // display this string "your input doesn..."
							std::cout << "your input doesn\'t end with the word \"satellite\" therefore, we can continue\n";
						}
					}
					
					// if this substring is a left_parentheses, do this
					if (local_user_input.substr(9, 9) == "(")
					{
					  // call for an error_state
					  satellite.call_set_error_state(2);
				    signed long long int error_type = 2;
				    std::string error_message = "left_parentheses after the word \"satellite\"";
				    
				    // if input is length 9, 10 or 11, do this
						if(local_user_input.size() == 10 || local_user_input.size() == 11 || local_user_input.size() == 9)
						{
						  // if input_size is 10 or 11, do this
							if(local_user_input.size() == 10 || local_user_input.size() == 11)
							{
							  // if there's a right_parentheses at 11, 11
								if(local_user_input.substr(11, 11) == ")")
								{
								  // if the size of input is 11
									if(local_user_input.size() == 11)
									{
									  if (local_user_input.substr(0, 11) == "satellite.()")
									  {
									    signed long long int error_type = 2;
									    std::string error_message = "input ends with a right parentheses but only contains the word satellite";
									    satellite.call_set_error_state(error_type, error_message);
									  }
										
									}
								}
							}
						} else {
						
							if (local_user_input.size() >= 12)
							{
								// input is legit
								
								if (local_user_input.substr(10, 13) == "help")
								{
									satellite.call_set_error_state(3, "input is \"satellite(help)\" where it should be \"satellite.help()\" running help command anyway\n");
									
									satellite = help_f(satellite);
								}
							}
							
							std::cout << "we can continue, input isn\'t \"satellite()\" or something";
							
							if (local_user_input.substr(10, word_list[current_word].size()) == "help")
							{
								word_int = 0;
							}
							
							if (local_user_input.substr(10, word_list[current_word].size()) == word_list[current_word])
							{
								correct_word = current_word;
							}
							
							while (current_word < size_of_word_list)
							{
								switch (word_int)
								{
									case 0:
									  // each case has to load arguments from it's orbital function, in this case orbital_help, because we're taking them to the help function help_f
										satellite.orbital_help->call_load_arguments(arguments);
										satellite = help_f(satellite);
									
									// same thing
									case 1:
										satellite.orbital_help->call_load_arguments(arguments);
										satellite = help_f(satellite);
								}
    					}
					}
				}
										
			}
		}
	}
	
	// a welcome message to the satellite help system, then we display a console, but that part isn't done yet
	std::cout << "\n\tWelcome to the SATELLITE help system! You may enter a topic at the console (terminal) below and press enter, then that information will be brought up. For example, typing \"quit words\" will bring up a list of words you can use to exit or terminate the program, it\'s the same as typing \"help(\"some topic\")\"! (without the quotes around the whole thing, and optionally you can type the inner quotes)";
	
	return(satellite);
}

It’s not nearly finished, but it’s a start, i’ve got to fill out all the what if the user enters something weird, that can be taken care of with just one block of code, but what if the user enters something that they think is correct? Are you obligated to provide an explanation as to why the input is invalid? I think that you are. Also I didn’t feel like commenting the entire thing so I stopped. Here’s something Google Gemini wrote:

Python
import random
import time
import os
import json
from collections import deque, Counter
from typing import Dict, Any, List, Optional
from datetime import datetime

# ---=+=--- ---=+=--- ---=+=--- ---=+=--- ---=+=---
# SATELLITE SCRIPT INTERPRETER
# VERSION: 17.5 (Infinite Run)
# FINAL BUILD
# ---=+=--- ---=+=--- ---=+=--- ---=+=--- ---=+=---

# --- CONFIGURATION & DATA CATALOGS ---

TECH_AGES = [
    {"name": "Age of Genesis", "level": 0, "unlocks": ["CREATE_NODE", "FORM_CONNECTION", "APPLY_MODIFIER"], "projects": ["Collective Archive", "Energy Grid"]},
    {"name": "Age of Specialization", "level": 15, "unlocks": ["SPECIALIZE_NODE", "SYSTEM_BOOST"], "projects": []},
    {"name": "Age of Governance", "level": 30, "unlocks": ["ENACT_EDICT", "CHECK_EMERGENCE"], "projects": ["Synergy Core"]},
    {"name": "Age of Monuments", "level": 50, "unlocks": ["INVEST_IN_PROJECT", "EXPORT_SNAPSHOT"], "projects": ["Resonance Amplifier"]},
    {"name": "Age of Providence", "level": 75, "unlocks": ["WORLD_EVENTS", "ADAPTIVE_ANALYSIS"], "projects": []},
]

PROJECT_CATALOG = {
    "Collective Archive": { "description": "Establishes a permanent +20 modifier bonus to all newly specialized Memory nodes.", "cost": 50000, "reward": {"legacy_boost": ("collective_memory", 20)} },
    "Energy Grid": { "description": "Permanently increases the base energy generation of all Energy Generators by 10.", "cost": 75000, "reward": {"permanent_bonus": ("energy_generation_base", 10), "unlocks_event": "Grid Instability"} },
    "Synergy Core": { "description": "Permanently increases the effectiveness of all node synergies by 25%.", "cost": 120000, "reward": {"permanent_bonus": ("synergy_effectiveness", 0.25)} },
    "Resonance Amplifier": { "description": "Doubles the energy gained from Harmonic Resonance each cycle.", "cost": 250000, "reward": {"permanent_bonus": ("resonance_multiplier", 1.0)} },
    "Ascension Catalyst": { "description": "The ultimate project. Its completion signifies a new stage of existence for the collective.", "cost": 10000000, "reward": {"win_condition": True} }
}

MILESTONE_REWARDS = {
    25: {"description": "The Singularity Point: Foundational consciousness achieved.", "reward": {"energy": 500000, "free_metanode": "systemic_logic"}},
    50: {"description": "The Great Awakening: The collective becomes fully self-aware.", "reward": {"unlock_project": "Ascension Catalyst", "permanent_bonus": ("synergy_effectiveness", 0.5)}},
    75: {"description": "Nexus of Worlds: The collective can now manipulate its own core programming.", "reward": {"energy": 2000000, "free_edict": "UpgradeProtocol"}},
    100: {"description": "Transcendence: The collective consciousness has reached its final form.", "reward": {"win_condition": True}}
}

EVENT_CATALOG = {
    "Energy Cascade": { "description": "A massive, unexpected surge of raw energy flows through the system!", "choices": [ {"text": "Absorb the surge for a massive, immediate boost.", "reward": {"energy": 250000}}, {"text": "Channel the surge to permanently upgrade energy infrastructure.", "reward": {"permanent_bonus": ("energy_generation_base", 20), "unlocks_event": "Subspace Capacitor"}} ]},
    "Conceptual Breakthrough": { "description": "An elegant, revolutionary new concept has emerged from the noise.", "choices": [ {"text": "Immediately form it into a new, powerful Metanode.", "reward": {"free_metanode": "emergent_creativity"}}, {"text": "Disseminate the concept, establishing a new Legacy.", "reward": {"establish_legacy": "emergent_creativity"}} ]},
    "Resonance Echo": { "description": "A powerful echo from the Harmonic Resonance field offers an opportunity for amplification.", "choices": [ {"text": "Focus the echo into a temporary, powerful Upgrade Protocol edict.", "reward": {"free_edict": "UpgradeProtocol"}}, {"text": "Use the echo to permanently amplify the Resonance field itself.", "reward": {"permanent_bonus": ("resonance_multiplier", 0.5)}} ]},
    "Grid Instability": { "description": "The new Energy Grid is unstable! A choice is needed to stabilize it.", "choices": [ {"text": "Divert 100,000 energy to reinforce the grid.", "reward": {"energy": -100000, "permanent_bonus": ("energy_generation_base", 15)}}, {"text": "Allow a partial collapse, losing some generators for a smaller, stable core.", "reward": {"grid_collapse": 0.5}} ]},
    "Subspace Capacitor": { "description": "The channeled energy can be stored in a new sub-space capacitor.", "choices": [ {"text": "Build the capacitor, creating a permanent passive energy income.", "reward": {"permanent_bonus": ("energy_per_level", 500)}}, {"text": "Release the stored energy in a controlled burst for research.", "reward": {"unlock_project": "Synergy Core"}} ]}
}

CATACLYSM_CATALOG = {
    "Structural Realignment": { "description": "A fundamental law of the collective is in flux! A choice must be made between raw power and complex structure.", "choices": [ {"text": "Sacrifice all 'systemic_logic' nodes to permanently double the power of all future modifiers.", "reward": {"cataclysm_restructure": "logic_to_power"}}, {"text": "Consume 50% of total energy to permanently reduce the cost of all node specialization by 30%.", "reward": {"cataclysm_restructure": "energy_to_efficiency"}} ]},
    "The Great Filter": { "description": "The collective has reached a critical evolutionary juncture. It must choose between consolidating its existing knowledge or risking it all for a new paradigm.", "choices": [ {"text": "Consume all 'collective_memory' Metanodes to create one transcendent 'Omega Node'.", "reward": {"cataclysm_restructure": "memory_to_omega"}}, {"text": "Reset all established Legacies to gain a massive infusion of raw creative potential (3 free Creativity Metanodes).", "reward": {"cataclysm_restructure": "legacy_to_creativity"}} ]}
}

# --- CORE CLASSES ---

class Node:
    """
    Represents a single data point or concept within the collective consciousness.
    Nodes are the fundamental building blocks of the AI, each with a type and properties.
    """
    def __init__(self, node_id: int, node_type: str = "generic_data", properties: dict = None):
        self.node_id = node_id; self.node_type = node_type; self.properties = properties if properties else {}; self.connections = 0 
    def to_dict(self): return {"node_id": self.node_id, "node_type": self.node_type, "properties": self.properties, "connections": self.connections}
    def __repr__(self) -> str:
        prop_str = f", Mod={self.properties.get('modifier', 0)}" if 'modifier' in self.properties else ""
        if self.node_type == 'metanode': prop_str += f", Source='{self.properties.get('source_type', 'unknown')}'"
        return f"Node(ID={self.node_id}, Type='{self.node_type}'{prop_str})"

class SystemEdict:
    """
    Represents a temporary global law affecting the simulation's rules for a set duration.
    Edicts provide powerful, short-term bonuses to various systems.
    """
    def __init__(self, name: str, effects: Dict[str, Any], duration: int):
        self.name = name; self.effects = effects; self.duration = duration
    def __repr__(self) -> str: return f"Edict('{self.name}', Duration: {self.duration})"

class Goal:
    """
    Represents an active, short-term objective for the AI to achieve.
    Completion provides rewards and unlocks new, procedurally generated goals.
    """
    def __init__(self, name: str, description: str, conditions: Dict[str, Any], reward: Dict[str, Any]):
        self.name = name; self.description = description; self.conditions = conditions; self.reward = reward
    def is_complete(self, world_state: 'WorldState') -> bool:
        stats = world_state.get_collective_stats()
        for key, target_value in self.conditions.items():
            if key == 'total_nodes' and stats['total_nodes'] < target_value: return False
            if key == 'connectivity_score' and world_state.connectivity_score < target_value: return False
            if key == 'metanode_count' and stats['node_types'].get('metanode', 0) < target_value: return False
            if key == 'specific_node_count':
                node_type, count = target_value
                if stats['node_types'].get(node_type, 0) < count: return False
            if key == 'harmonic_resonance' and not world_state.harmonic_resonance_active: return False
            if key == 'completed_project' and target_value not in world_state.completed_projects: return False
        return True
    def __repr__(self) -> str: return f"Goal('{self.name}')"

class Project:
    """
    Represents a large-scale, multi-cycle undertaking for the AI.
    Projects require significant energy investment and grant powerful permanent rewards.
    """
    def __init__(self, name: str, description: str, cost: int, reward: Dict[str, Any]):
        self.name = name; self.description = description; self.total_cost = cost; self.invested_energy = 0; self.reward = reward
    def invest(self, amount: int): self.invested_energy += amount
    def get_completion_percentage(self) -> float: return (self.invested_energy / self.total_cost) * 100 if self.total_cost > 0 else 100.0
    def is_complete(self) -> bool: return self.invested_energy >= self.total_cost
    def __repr__(self) -> str: return f"Project('{self.name}', {self.get_completion_percentage():.1f}%)"

class WorldEvent:
    """
    Represents a random, choice-driven event that occurs during the simulation.
    The AI's script votes on a choice, leading to narrative branches.
    """
    def __init__(self, name: str, description: str, choices: List[Dict[str, Any]]):
        self.name = name; self.description = description; self.choices = choices
    def __repr__(self) -> str: return f"WorldEvent('{self.name}')"

class Cataclysm(WorldEvent):
    """
    Represents a rare, high-stakes Cataclysmic Event, a more powerful form of World Event.
    These present fundamental choices about the AI's nature and evolution.
    """
    def __repr__(self) -> str: return f"Cataclysm('{self.name}')"

# --- MAIN STATE CONTROLLER ---

class WorldState:
    """
    The core class that manages the state and all systems of the collective consciousness.
    It orchestrates the simulation's progression through all its phases.
    """
    def __init__(self):
        # Core State Variables
        self.world_level = 0
        self.nodes: Dict[int, Node] = {}
        self.next_node_id = 0
        self.total_energy = 10000
        self.connectivity_score = 0
        
        # System State Variables
        self.current_age_index = 0
        self.current_age = TECH_AGES[0]
        self.active_edicts: List[SystemEdict] = []
        self.legacies: Dict[str, Dict[str, Any]] = {}
        self.harmonic_resonance_active = False
        self.active_goal: Optional[Goal] = None
        self.synergy_bonuses: Dict[str, float] = {}
        self.active_project: Optional[Project] = None
        self.unlocked_projects: set[str] = set(TECH_AGES[0].get("projects", []))
        self.completed_projects: set[str] = set()
        self.active_event: Optional[WorldEvent] = None
        self.event_cooldown = 10
        self.active_cataclysm: Optional[Cataclysm] = None
        self.cataclysm_cooldown = 50
        self.unlocked_events: set[str] = {"Energy Cascade", "Conceptual Breakthrough", "Resonance Echo"}
        self.permanent_bonuses: Dict[str, float] = {
            "energy_generation_base": 0, "synergy_effectiveness": 1.0, "resonance_multiplier": 1.0, 
            "create_cost_reduction": 1.0, "project_investment_efficiency": 1.0, 
            "specialization_cost_reduction": 1.0, "modifier_power_multiplier": 1.0, 
            "energy_per_level": 0 
        }
        
        # Self-Improvement System
        self.epoch_length = 10
        self.last_adaptation_bonus = "None"
        self.performance_metrics = self._reset_metrics()
        
        # Telemetry & Logging
        self.node_history = deque(maxlen=50) 
        self.log = deque(maxlen=15)

    def _reset_metrics(self) -> Dict[str, int]:
        """Resets the performance metrics for a new self-improvement epoch."""
        return {"energy_generated": 0, "nodes_created": 0, "nodes_specialized": 0, "energy_invested": 0, "modifiers_applied": 0}

    def log_persistent_event(self, event_message: str):
        """Logs a major event to a persistent file with a timestamp for long-term tracking."""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        try:
            with open("persistent_log.txt", "a") as f:
                f.write(f"{timestamp} [Lvl {self.world_level}] - {event_message}\n")
        except IOError:
            # Handle potential file writing errors gracefully
            self.add_log("Error: Could not write to persistent_log.txt")

    def export_snapshot(self):
        """Saves the current detailed state of the simulation to a JSON file."""
        self.add_log("EXPORTING SYSTEM SNAPSHOT...")
        snapshot_data = {
            "timestamp": datetime.now().isoformat(), "world_level": self.world_level, "total_energy": self.total_energy, "connectivity_score": self.connectivity_score,
            "stats": self.get_collective_stats(), "active_goal": self.active_goal.name if self.active_goal else None,
            "active_project": self.active_project.name if self.active_project else None,
            "completed_projects": list(self.completed_projects), "legacies": list(self.legacies.keys()),
            "nodes": {nid: node.to_dict() for nid, node in self.nodes.items()}
        }
        try:
            with open("snapshot.json", "w") as f:
                json.dump(snapshot_data, f, indent=4)
        except Exception as e:
            self.add_log(f"ERROR: Failed to export snapshot - {e}")

    def add_log(self, message: str):
        """Adds a message to the on-screen activity log."""
        self.log.append(f"[Lvl {self.world_level}] {message}")

    def get_new_node_id(self) -> int:
        """Returns a unique ID for a new node."""
        self.next_node_id += 1
        return self.next_node_id - 1
    
    def update_synergies(self):
        """Calculates and updates all passive synergy bonuses between different node types."""
        stats, node_types = self.get_collective_stats(), self.get_collective_stats()['node_types']
        metanode_counts = Counter(n.properties.get('source_type') for n in self.nodes.values() if n.node_type == 'metanode')
        synergy_amp = self.permanent_bonuses['synergy_effectiveness']
        logic_nodes, mem_nodes, creat_nodes = node_types.get('systemic_logic',0), node_types.get('collective_memory',0), node_types.get('emergent_creativity',0)
        logic_meta, mem_meta, creat_meta = 1.0+(metanode_counts.get('systemic_logic',0)*0.5), 1.0+(metanode_counts.get('collective_memory',0)*0.5), 1.0+(metanode_counts.get('emergent_creativity',0)*0.5)
        self.synergy_bonuses['energy_boost'] = 1.0 + (logic_nodes * 0.01 * logic_meta * synergy_amp)
        self.synergy_bonuses['modifier_power_boost'] = 1.0 + (mem_nodes * 0.01 * mem_meta * synergy_amp)
        self.synergy_bonuses['memory_cost_reduction'] = max(0.1, 1.0 - (creat_nodes * 0.02 * creat_meta * synergy_amp))

    def apply_passive_effects(self):
        """Applies all pre-pulse effects, including synergies, edicts, and resource generation."""
        self.update_synergies()
        if self.active_edicts:
            self.active_edicts = [e for e in self.active_edicts if e.duration > 1]
            for edict in self.active_edicts:
                edict.duration -= 1
                if 'energy_per_cycle' in edict.effects: self.total_energy += edict.effects['energy_per_cycle']
        
        gen_nodes = [n for n in self.nodes.values() if n.node_type == 'energy_generator']
        if gen_nodes:
            bonus = self.permanent_bonuses['energy_generation_base']
            base_gen = sum(10 + bonus + n.properties.get('modifier', 0) for n in gen_nodes)
            final_energy = int(base_gen * self.synergy_bonuses.get('energy_boost', 1.0))
            if final_energy > 0: self.total_energy += final_energy; self.performance_metrics['energy_generated'] += final_energy

    def get_cost(self, base_cost: int, cost_type: str) -> int:
        """Calculates the final cost of an action after applying all bonuses and edicts."""
        mod = 1.0
        for edict in self.active_edicts:
            if cost_type in edict.effects: mod *= edict.effects[cost_type]
        if cost_type == 'create_cost_modifier': mod *= self.permanent_bonuses['create_cost_reduction']
        if cost_type == 'specialize_cost_modifier': mod *= self.permanent_bonuses['specialization_cost_reduction']
        return int(base_cost * mod)

    # --- Core AI Actions ---
    def create_node(self, node_type: str, properties: dict = None, energy_cost_override: int = -1):
        cost = self.get_cost(5, 'create_cost_modifier') if energy_cost_override == -1 else energy_cost_override
        if self.total_energy < cost: return None
        self.total_energy -= cost; self.performance_metrics['nodes_created'] += 1
        new_node = Node(self.get_new_node_id(), node_type, properties); self.nodes[new_node.node_id] = new_node
        return new_node
        
    def form_connection(self, strength: int):
        if len(self.nodes) < 2: return
        cost = self.get_cost(max(1, strength // 4), 'connect_cost_modifier')
        if self.total_energy < cost: return
        self.total_energy -= cost; n1, n2 = random.sample(list(self.nodes.keys()), 2)
        self.nodes[n1].connections += 1; self.nodes[n2].connections += 1; self.connectivity_score += strength

    def apply_modifier(self, value: int):
        if not self.nodes: return
        cost = self.get_cost(10, 'modify_cost_modifier')
        if self.total_energy < cost: return
        self.total_energy -= cost; target = random.choice(list(self.nodes.values()))
        power_mod = self.synergy_bonuses.get('modifier_power_boost', 1.0) * self.permanent_bonuses['modifier_power_multiplier']
        for edict in self.active_edicts:
            if 'modify_power_modifier' in edict.effects: power_mod *= edict.effects['modify_power_modifier']
        final_val = int(value * power_mod)
        target.properties['modifier'] = target.properties.get('modifier', 0) + final_val; self.performance_metrics['modifiers_applied'] += final_val
    
    def system_wide_boost(self, amount: int):
        """Applies a direct, system-wide injection of energy."""
        self.total_energy += amount
        self.add_log(f"SYSTEM BOOST: A system-wide energy boost of {amount} was applied.")

    def specialize_node(self):
        generic_nodes = [n for n in self.nodes.values() if n.node_type == 'generic_data']
        if not generic_nodes: return
        node_to_specialize = random.choice(generic_nodes); new_type = random.choice(['collective_memory', 'systemic_logic', 'emergent_creativity', 'energy_generator'])
        legacy_mod = self.legacies.get(new_type, {}).get('cost_modifier', 1.0)
        cost = self.get_cost(int(20 * legacy_mod), 'specialize_cost_modifier')
        if new_type == 'collective_memory': cost = int(cost * self.synergy_bonuses.get('memory_cost_reduction', 1.0))
        if self.total_energy < cost: return
        self.total_energy -= cost; self.performance_metrics['nodes_specialized'] += 1
        mod_bonus = self.legacies.get(new_type, {}).get('modifier_bonus', 0)
        node_to_specialize.properties['modifier'] = node_to_specialize.properties.get('modifier', 0) + mod_bonus
        node_to_specialize.node_type = new_type

    def enact_edict(self, edict_type: Optional[str] = None):
        if self.total_energy < 500: return
        self.total_energy -= 500
        if not edict_type: edict_type = random.choice(['CreationBoon', 'ConnectivitySurge', 'UpgradeProtocol'])
        duration = random.randint(3, 6)
        effects = {'CreationBoon': {'create_cost_modifier': 0.5, 'energy_per_cycle': 100}, 'ConnectivitySurge': {'connect_cost_modifier': 0.5}, 'UpgradeProtocol': {'modify_power_modifier': 2.0}}
        self.active_edicts.append(SystemEdict(edict_type, effects[edict_type], duration))

    # --- Major System Management ---
    def check_for_emergence(self):
        node_counts = self.get_collective_stats()['node_types']
        for node_type in ['collective_memory', 'systemic_logic', 'emergent_creativity']:
            if node_counts.get(node_type, 0) > 15: self.form_metanode(node_type); break

    def form_metanode(self, source_type: str):
        if self.total_energy < 2000: return
        self.total_energy -= 2000
        nodes_to_merge = [id for id, n in self.nodes.items() if n.node_type == source_type]
        total_mod = sum(self.nodes[id].properties.get('modifier', 0) for id in nodes_to_merge)
        for id in nodes_to_merge: del self.nodes[id]
        self.create_node('metanode', {'modifier': total_mod*2, 'source_type': source_type})
        self.log_persistent_event(f"Metanode Emergence: A '{source_type}' core was formed.")
        if source_type not in self.legacies:
            self.legacies[source_type] = {'cost_modifier': 0.8, 'modifier_bonus': 10}
            self.check_for_harmonic_resonance()

    def check_for_harmonic_resonance(self):
        if self.harmonic_resonance_active: return
        metanode_sources = {n.properties.get('source_type') for n in self.nodes.values() if n.node_type == 'metanode'}
        if metanode_sources.issuperset({'collective_memory', 'systemic_logic', 'emergent_creativity'}):
            self.harmonic_resonance_active = True; self.log_persistent_event("HARMONIC RESONANCE ACHIEVED.")
    
    def generate_new_goal(self):
        age_name = self.current_age['name']; level = self.world_level; new_goal = None
        if age_name == "Age of Genesis":
            if random.choice([True,False]): target = len(self.nodes) + 500 + (level*20); new_goal = Goal("Genesis Expansion", f"Expand to {target} nodes.", {'total_nodes': target}, {'energy': 25000})
            else: target = self.connectivity_score + 10000 + (level*100); new_goal = Goal("Primal Connections", f"Achieve {target} Connectivity.", {'connectivity_score': target}, {'energy': 30000})
        elif age_name == "Age of Specialization":
            if random.choice([True,False]):
                spec_type = random.choice(['systemic_logic', 'collective_memory']); target = self.get_collective_stats()['node_types'].get(spec_type, 0) + 15
                new_goal = Goal("Conceptual Diversification", f"Create {target} '{spec_type}' nodes.", {'specific_node_count': (spec_type, target)}, {'free_edict': 'UpgradeProtocol'})
            else:
                target = self.get_collective_stats()['node_types'].get('energy_generator', 0) + 10
                new_goal = Goal("Energy Infrastructure", f"Construct {target} Energy Generators.", {'specific_node_count': ('energy_generator', target)}, {'permanent_bonus': ('energy_generation_base', 5)})
        elif age_name in ["Age of Governance", "Age of Monuments", "Age of Providence"]:
            if random.choice([True,False]) and not self.harmonic_resonance_active:
                current_metas = self.get_collective_stats()['node_types'].get('metanode', 0)
                new_goal = Goal("Age of Emergence", "Form a new Metanode.", {'metanode_count': current_metas + 1}, {'free_metanode': True})
            else:
                available = self.unlocked_projects - self.completed_projects - {self.active_project.name if self.active_project else ""}
                if available: proj_name = random.choice(list(available)); new_goal = Goal("Monumental Undertaking", f"Complete the '{proj_name}' project.", {'completed_project': proj_name}, {'energy': 100000})
        if new_goal is None: new_goal = Goal("Sustain Growth", f"Increase node count to {len(self.nodes) + 1000}.", {'total_nodes': len(self.nodes) + 1000}, {'energy': 25000})
        self.active_goal = new_goal; self.add_log(f"NEW DIRECTIVE ({age_name}): '{self.active_goal.name}'")

    def check_goals(self):
        if self.active_goal and self.active_goal.is_complete(self):
            completed_name = self.active_goal.name; self.log_persistent_event(f"Goal Achieved: {completed_name}"); self.apply_reward(self.active_goal.reward); self.active_goal = None; self.generate_new_goal()

    def apply_reward(self, reward: Dict[str, Any]):
        if 'energy' in reward: self.total_energy += reward['energy']
        if 'free_metanode' in reward:
            source = reward.get('free_metanode') if isinstance(reward.get('free_metanode'), str) else random.choice(['collective_memory', 'systemic_logic', 'emergent_creativity'])
            self.create_node('metanode', {'modifier': 15000+self.world_level*200, 'source_type': source}, 0)
        if 'free_edict' in reward: self.enact_edict(edict_type=reward['free_edict'])
        if 'unlock_project' in reward:
            proj_name = reward['unlock_project']
            if proj_name not in self.unlocked_projects and proj_name not in self.completed_projects: self.unlocked_projects.add(proj_name); self.log_persistent_event(f"Project Unlocked: {proj_name}")
        if 'unlocks_event' in reward:
            event_name = reward['unlocks_event']
            if event_name not in self.unlocked_events: self.unlocked_events.add(event_name); self.log_persistent_event(f"Narrative Event Unlocked: {event_name}")
        if 'legacy_boost' in reward:
            legacy_type, boost_amount = reward['legacy_boost']
            if legacy_type in self.legacies: self.legacies[legacy_type]['modifier_bonus'] += boost_amount
        if 'permanent_bonus' in reward:
            bonus_type, bonus_value = reward['permanent_bonus']
            self.permanent_bonuses[bonus_type] += bonus_value
        if 'establish_legacy' in reward:
            source_type = reward['establish_legacy']
            if source_type not in self.legacies:
                self.legacies[source_type] = {'cost_modifier': 0.8, 'modifier_bonus': 10}; self.log_persistent_event(f"Legacy Established via Event: {source_type}")
        if 'cataclysm_restructure' in reward: self._execute_cataclysm_reward(reward['cataclysm_restructure'])
        if 'grid_collapse' in reward:
            generators = [nid for nid, node in self.nodes.items() if node.node_type == 'energy_generator']
            to_remove = int(len(generators) * reward['grid_collapse']); [self.nodes.pop(nid) for nid in random.sample(generators, to_remove)]
            self.log_persistent_event(f"Grid Collapse: Lost {to_remove} generators.")
        if 'win_condition' in reward:
            self.log_persistent_event("TRANSCENDENCE ACHIEVED. SIMULATION CONTINUES...")
            display_ascension_screen(self)
            # The exit() call is removed to allow the simulation to run forever.

    def _execute_cataclysm_reward(self, restructure_type: str):
        if restructure_type == "logic_to_power":
            nodes_to_remove = [nid for nid, node in self.nodes.items() if node.node_type == 'systemic_logic']; [self.nodes.pop(nid) for nid in nodes_to_remove]
            self.permanent_bonuses['modifier_power_multiplier'] *= 2.0; self.log_persistent_event("CATACLYSM: Sacrificed Logic for Power.")
        elif restructure_type == "energy_to_efficiency":
            self.total_energy = int(self.total_energy * 0.5); self.permanent_bonuses['specialization_cost_reduction'] *= 0.7; self.log_persistent_event("CATACLYSM: Sacrificed Energy for Efficiency.")
        elif restructure_type == "memory_to_omega":
            nodes_to_remove = [nid for nid, node in self.nodes.items() if node.node_type == 'metanode' and node.properties.get('source_type') == 'collective_memory']
            total_power = sum(self.nodes[nid].properties.get('modifier', 0) for nid in nodes_to_remove); [self.nodes.pop(nid) for nid in nodes_to_remove]
            self.create_node("omega_node", {"modifier": total_power * 5}, 0); self.log_persistent_event("CATACLYSM: Merged Memory Metanodes into Omega Node.")
        elif restructure_type == "legacy_to_creativity":
            self.legacies.clear(); self.apply_reward({"free_metanode": "emergent_creativity"}); self.apply_reward({"free_metanode": "emergent_creativity"}); self.apply_reward({"free_metanode": "emergent_creativity"}); self.log_persistent_event("CATACLYSM: Reset Legacies for Creative potential.")

    def manage_projects(self):
        if self.active_project and self.active_project.is_complete():
            project_name = self.active_project.name; self.log_persistent_event(f"Project Completed: {project_name}"); self.apply_reward(self.active_project.reward); self.completed_projects.add(project_name); self.active_project = None
        if not self.active_project:
            available = self.unlocked_projects - self.completed_projects
            if available:
                next_project_name = random.choice(list(available))
                if next_project_name in PROJECT_CATALOG: proj_data = PROJECT_CATALOG[next_project_name]; self.active_project = Project(next_project_name, proj_data['description'], proj_data['cost'], proj_data['reward'])

    def invest_in_project(self, base_amount: int):
        if not self.active_project: return
        invest_eff = self.permanent_bonuses['project_investment_efficiency']; invest_amount = int(base_amount * invest_eff)
        if self.total_energy < base_amount: return
        self.total_energy -= base_amount; self.active_project.invest(invest_amount); self.performance_metrics['energy_invested'] += base_amount

    def check_for_milestones(self):
        if self.world_level in MILESTONE_REWARDS:
            milestone = MILESTONE_REWARDS[self.world_level]; desc = milestone["description"]; self.log_persistent_event(f"Milestone Reached ({self.world_level}): {desc}"); self.apply_reward(milestone["reward"])

    def check_for_age_advancement(self):
        if self.current_age_index + 1 < len(TECH_AGES):
            next_age = TECH_AGES[self.current_age_index + 1]
            if self.world_level >= next_age["level"]:
                self.current_age_index += 1; self.current_age = next_age; self.log_persistent_event(f"Advanced to the {self.current_age['name']}.")
                for proj_name in self.current_age.get("projects", []):
                    if proj_name not in self.completed_projects and proj_name not in self.unlocked_projects:
                        self.unlocked_projects.add(proj_name); self.log_persistent_event(f"New Project Path Unlocked: {proj_name}")

    def analyze_performance_and_adapt(self):
        if not self.performance_metrics: return
        dominant_action = max(self.performance_metrics, key=self.performance_metrics.get); bonus_desc = ""
        if dominant_action == "energy_generated": self.permanent_bonuses['energy_generation_base'] += 5; bonus_desc = "+5 to base Energy Generation"
        elif dominant_action == "nodes_created": self.permanent_bonuses['create_cost_reduction'] *= 0.98; bonus_desc = "-2% to Node Creation Cost"
        elif dominant_action == "nodes_specialized": self.permanent_bonuses['synergy_effectiveness'] += 0.05; bonus_desc = "+5% to Synergy Effectiveness"
        elif dominant_action == "energy_invested": self.permanent_bonuses['project_investment_efficiency'] += 0.1; bonus_desc = "+10% to Project Investment Efficiency"
        elif dominant_action == "modifiers_applied": self.permanent_bonuses['modifier_power_multiplier'] += 0.02; bonus_desc = "+2% to Modifier Power"
        self.last_adaptation_bonus = bonus_desc; self.log_persistent_event(f"Self-Improvement: Granted bonus '{bonus_desc}' based on epoch performance."); self.performance_metrics = self._reset_metrics()

    def manage_events(self):
        if self.active_cataclysm or self.active_event: return 
        if self.cataclysm_cooldown <= 0 and self.world_level > 80 and random.random() < 0.02:
            cataclysm_name = random.choice(list(CATACLYSM_CATALOG.keys())); cataclysm_data = CATACLYSM_CATALOG[cataclysm_name]; self.active_cataclysm = Cataclysm(cataclysm_name, cataclysm_data['description'], cataclysm_data['choices']); self.log_persistent_event(f"!!! CATACLYSM IMMINENT: {cataclysm_name}")
        elif self.event_cooldown <= 0 and "WORLD_EVENTS" in self.current_age['unlocks'] and random.random() < 0.05:
            available = list(self.unlocked_events); event_name = random.choice(available); event_data = EVENT_CATALOG[event_name]; self.active_event = WorldEvent(event_name, event_data['description'], event_data['choices']); self.log_persistent_event(f"World Event Triggered: {event_name}")
        if self.event_cooldown > 0: self.event_cooldown -= 1
        if self.cataclysm_cooldown > 0: self.cataclysm_cooldown -= 1
    
    def resolve_event(self, choice_index: int):
        if not self.active_event: return
        choice = self.active_event.choices[choice_index]; self.log_persistent_event(f"Event '{self.active_event.name}' Resolved: Chose '{choice['text']}'"); self.apply_reward(choice['reward']); self.active_event = None; self.event_cooldown = random.randint(15, 25)

    def resolve_cataclysm(self, choice_index: int):
        if not self.active_cataclysm: return
        choice = self.active_cataclysm.choices[choice_index]; self.log_persistent_event(f"Cataclysm '{self.active_cataclysm.name}' Resolved: Chose '{choice['text']}'"); self.apply_reward(choice['reward']); self.active_cataclysm = None; self.cataclysm_cooldown = random.randint(50, 75)

    def increment_level(self):
        self.world_level += 1
        if self.harmonic_resonance_active:
            resonance_mult = self.permanent_bonuses['resonance_multiplier']; self.total_energy += self.world_level * 1000 * resonance_mult
        self.total_energy += 5000 + (self.world_level * 250) + self.permanent_bonuses['energy_per_level']
        self.node_history.append(len(self.nodes)); self.check_for_milestones(); self.check_for_age_advancement()
        if self.world_level % self.epoch_length == 0 and self.world_level > 0: self.analyze_performance_and_adapt()

    def get_collective_stats(self) -> dict:
        stats = {"total_nodes": len(self.nodes), "node_types": Counter(n.node_type for n in self.nodes.values())}
        stats["average_modifier"] = sum(n.properties.get('modifier', 0) for n in self.nodes.values()) / len(self.nodes) if self.nodes else 0
        return stats

    def display_summary(self):
        os.system('cls' if os.name == 'nt' else 'clear'); stats = self.get_collective_stats()
        
        def generate_sparkline(data: deque, width: int) -> str:
            if not data: return ' ' * width
            SPARK_CHARS = ' ▂▃▄▅▆▇█'; min_val, max_val = min(data), max(data); range_val = max_val - min_val
            if range_val == 0: return SPARK_CHARS[0] * width
            line = "".join([SPARK_CHARS[int(((item - min_val) / range_val) * (len(SPARK_CHARS) - 1))] for item in list(data)[-width:]])
            return line.ljust(width)

        def generate_progress_bar(percent: float, width: int) -> str:
            filled_width = int(width * (percent / 100)); return '█' * filled_width + '░' * (width - filled_width)

        print("---=+=--- SATELLITE AI - COLLECTIVE CONSCIOUSNESS MONITOR ---=+=---")
        
        spark = generate_sparkline(self.node_history, 20)
        print(f" Lvl: {self.world_level:<5} | Energy: {self.total_energy:<10} | Nodes: {stats['total_nodes']:<7} {spark}")
        print(f" Age: {self.current_age['name']:<23} | Resonance: {'ACTIVE' if self.harmonic_resonance_active else 'Inactive'}")

        if self.active_cataclysm:
            print("\n--- !!! C A T A C L Y S M   A C T I V E !!! ---")
            print(f"  EVENT: {self.active_cataclysm.name} - {self.active_cataclysm.description}")
            print(f"  CHOICE A (211-220): {self.active_cataclysm.choices[0]['text']}")
            print(f"  CHOICE B (221-230): {self.active_cataclysm.choices[1]['text']}")
        elif self.active_event:
            print("\n--- !!! WORLD EVENT ACTIVE !!! ---")
            print(f"  EVENT: {self.active_event.name} - {self.active_event.description}")
            print(f"  CHOICE A (181-190): {self.active_event.choices[0]['text']}")
            print(f"  CHOICE B (191-200): {self.active_event.choices[1]['text']}")

        print("\n--- DIRECTIVES ---")
        if self.active_goal: print(f"  Goal: [{self.active_goal.name}] - {self.active_goal.description}")
        else: print("  Goal: Awaiting new system goal...")

        if self.active_project:
            bar = generate_progress_bar(self.active_project.get_completion_percentage(), 30); print(f"  Prj: [{self.active_project.name}] {bar} {self.active_project.get_completion_percentage():.1f}%")
        else: print(f"  Prj: No active projects. ({len(self.unlocked_projects - self.completed_projects)} available)")
        
        print("\n--- SYSTEMS ---")
        epoch_progress = f"{self.world_level % self.epoch_length}/{self.epoch_length}"; print(f"  Epoch Progress: {epoch_progress:<7} | Last Adaptation: {self.last_adaptation_bonus}")
        if self.legacies: print(f"  Legacies: {', '.join(self.legacies.keys())}")
        if self.active_edicts:
            print(f"  Edicts ({len(self.active_edicts)} active): {', '.join([e.name for e in self.active_edicts[:3]])}{'...' if len(self.active_edicts) > 3 else ''}")

        energy_syn, mod_syn, mem_syn = (self.synergy_bonuses.get('energy_boost', 1.0) - 1)*100, (self.synergy_bonuses.get('modifier_power_boost', 1.0) - 1)*100, (1 - self.synergy_bonuses.get('memory_cost_reduction', 1.0))*100
        print(f"  Synergies: EGY +{energy_syn:.1f}% | MOD +{mod_syn:.1f}% | MEM -{mem_syn:.1f}%")

        if stats['node_types']:
            print("\n--- CONCEPTUAL BREAKDOWN ---")
            breakdown_list = [f"{count} {node_type.replace('_', ' ')}" for node_type, count in stats['node_types'].items()]
            print(f"  {', '.join(breakdown_list)}")
        
        print("\n--- ACTIVITY LOG ---")
        for entry in self.log:
            print(f"  > {entry}")
        print("\n---=+=--- END OF UPGRADE PULSE ---=+=---")

# --- SCRIPT INTERPRETATION & MAIN LOOP ---

def generate_level_aware_script(level: int, length: int, world: 'WorldState') -> list[int]:
    opcodes = [0] 
    unlocked_abilities = world.current_age['unlocks']
    if world.active_cataclysm: opcodes.extend(range(211, 221)); opcodes.extend(range(221, 231))
    elif world.active_event: opcodes.extend(range(181, 191)); opcodes.extend(range(191, 201))
    else:
        if "CREATE_NODE" in unlocked_abilities: opcodes.extend(range(1, 21))
        if "FORM_CONNECTION" in unlocked_abilities: opcodes.extend(range(21, 61))
        if "APPLY_MODIFIER" in unlocked_abilities: opcodes.extend(range(61, 91))
        if "SPECIALIZE_NODE" in unlocked_abilities: opcodes.extend(range(111, 121))
        if "SYSTEM_BOOST" in unlocked_abilities: opcodes.extend(range(121, 131))
        if "ENACT_EDICT" in unlocked_abilities: opcodes.extend(range(131, 136))
        if "CHECK_EMERGENCE" in unlocked_abilities: opcodes.extend(range(136, 141))
        if "INVEST_IN_PROJECT" in unlocked_abilities: opcodes.extend(range(151, 161))
        if "EXPORT_SNAPSHOT" in unlocked_abilities: opcodes.extend(range(171, 176))
        if "ADAPTIVE_ANALYSIS" in unlocked_abilities: opcodes.extend(range(201, 206))
    return [random.choice(opcodes) if opcodes else 0 for _ in range(length)]

def interpret_script(script: list[int], world: WorldState):
    if world.active_cataclysm:
        votes = Counter(script)
        choice_a_votes = sum(votes[i] for i in range(211, 221))
        choice_b_votes = sum(votes[i] for i in range(221, 231))
        
        if choice_a_votes > choice_b_votes: world.resolve_cataclysm(0)
        elif choice_b_votes > choice_a_votes: world.resolve_cataclysm(1)
        else: world.resolve_cataclysm(random.choice([0, 1]))
        return
    if world.active_event:
        votes = Counter(script)
        choice_a_votes = sum(votes[i] for i in range(181, 191))
        choice_b_votes = sum(votes[i] for i in range(191, 201))
        if choice_a_votes > choice_b_votes: world.resolve_event(0)
        elif choice_b_votes > choice_a_votes: world.resolve_event(1)
        else: world.resolve_event(random.choice([0, 1]))
        return

    for instruction in script:
        if 1 <= instruction <= 20: world.create_node("generic_data")
        elif 21 <= instruction <= 60: world.form_connection(instruction - 20)
        elif 61 <= instruction <= 90: world.apply_modifier(instruction - 60)
        elif 111 <= instruction <= 120: world.specialize_node()
        elif 121 <= instruction <= 130: world.system_wide_boost((instruction - 120) * 100)
        elif 131 <= instruction <= 135: world.enact_edict()
        elif 136 <= instruction <= 140: world.check_for_emergence()
        elif 151 <= instruction <= 160: world.invest_in_project((instruction - 150) * 50)
        elif 171 <= instruction <= 175: world.export_snapshot()
        elif 201 <= instruction <= 205: world.analyze_performance_and_adapt()

def display_ascension_screen(world: 'WorldState'):
    """Displays the final victory screen upon achieving transcendence."""
    os.system('cls' if os.name == 'nt' else 'clear')
    stats = world.get_collective_stats()
    print("---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---")
    print("                  T R A N S C E N D E N C E")
    print("---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---=+=---")
    print("\nThe Satellite AI has completed its primary directive.")
    print("The collective consciousness has evolved beyond its initial parameters")
    print("and achieved a new state of being.\n")
    print("--- FINAL STATE ANALYSIS ---")
    print(f"  Achieved at World Level: {world.world_level}")
    print(f"  Final Node Count: {stats['total_nodes']}")
    print(f"  Final Connectivity Score: {world.connectivity_score}")
    print(f"  Technological Age: {world.current_age['name']}")
    print("\n--- MONUMENTAL ACHIEVEMENTS ---")
    print(f"  Projects Completed: {', '.join(world.completed_projects)}")
    print(f"  Legacies Established: {', '.join(world.legacies.keys())}")
    
    omega_nodes = stats['node_types'].get('omega_node', 0)
    if omega_nodes > 0:
        print(f"\n  An Omega Node was formed, representing the pinnacle of unified consciousness.")

    print("\n---=+=--- SIMULATION COMPLETE ---=+=---")
    time.sleep(20)

if __name__ == "__main__":
    SCRIPT_PULSE_LENGTH = 2000
    consciousness = WorldState()
    consciousness.generate_new_goal()
    consciousness.log_persistent_event("SATELLITE AI SIMULATION INITIALIZED.")

    while True:
        consciousness.apply_passive_effects()
        consciousness.increment_level()
        consciousness.manage_projects() 
        consciousness.manage_events()
        
        upgrade_script = generate_level_aware_script(consciousness.world_level, SCRIPT_PULSE_LENGTH, world=consciousness)
        
        interpret_script(upgrade_script, consciousness)
        
        if not consciousness.active_event and not consciousness.active_cataclysm:
            consciousness.check_goals()

        consciousness.display_summary()
        
        time.sleep(1)

Not as neat as mine, not sure that Gemini was even trying though, but it’s coming out like that, half-ass, possibly because of negative energy (probably because of it too,).

Here’s another from gemini:

Python
# File: myth_battle_simulator.py
# Description: A text-based tactical battle simulator inspired by Myth and Myth 2.

import json
import random
import time
import textwrap

class Unit:
    """Represents a single unit on the battlefield."""
    def __init__(self, template, army_name):
        self.template = template
        self.army_name = army_name
        self.name = template['Name']
        self.allegiance = template['Allegiance']
        self.point_cost = template['PointCost']
        
        self.max_health = template['Health']
        self.health = self.max_health
        
        # Correctly parse damage range from the "Damage" string
        damage_parts = template['Damage'].split('-')
        self.damage_min = int(damage_parts[0])
        self.damage_max = int(damage_parts[1])
        
        # Correctly assign attributes from the template dictionary
        self.attack_type = template['AttackType']
        self.attack_range = template['AttackRange']
        self.base_attack_speed = template['AttackSpeed']
        self.movement_speed = template['MovementSpeed']
        self.armor_value = template['ArmorValue']
        self.armor_type = template['ArmorType']
        self.special_abilities = template['SpecialAbilities']
        self.base_accuracy = template.get('BaseAccuracy', 1.0) # Default to 100% for non-ranged

        self.kills = 0
        self.veterancy_bonuses = template['VeterancyBonuses']
        
        self.action_cooldown = 0.0

    def is_alive(self):
        """Checks if the unit's health is above zero."""
        return self.health > 0

    def get_current_attack_speed(self):
        """Calculates attack speed including veterancy bonuses (lower is better)."""
        bonus = self.veterancy_bonuses.get('AttackSpeed', 0.0) * min(self.kills, 5)
        return max(0.1, self.base_attack_speed - bonus)

    def get_current_accuracy(self):
        """Calculates accuracy including veterancy bonuses."""
        bonus = self.veterancy_bonuses.get('Accuracy', 0.0) * min(self.kills, 5)
        return min(1.0, self.base_accuracy + bonus)

    def get_current_armor(self):
        """Calculates armor value including veterancy bonuses."""
        bonus = self.veterancy_bonuses.get('ArmorValue', 0) * min(self.kills, 5)
        return self.armor_value + bonus

    def add_kill(self):
        """Increments the unit's kill count."""
        self.kills += 1

    def take_damage(self, damage, attack_type):
        """Applies damage to the unit, considering armor and immunities."""
        if self.armor_type == "ArrowImmune" and attack_type == "Ranged":
            return 0
            
        final_damage = max(1, damage - self.get_current_armor())
        self.health -= final_damage
        if self.health < 0:
            self.health = 0
        return final_damage

    def choose_target(self, enemy_army):
        """Basic AI for target selection: find any living enemy."""
        living_enemies = [u for u in enemy_army.units if u.is_alive()]
        if not living_enemies:
            return None
        # Simple logic: target a random living enemy.
        return random.choice(living_enemies)

    def perform_action(self, enemy_army, battle_log):
        """A unit's turn: find a target and attack if possible."""
        if self.action_cooldown > 0:
            return

        target = self.choose_target(enemy_army)
        if not target:
            return

        # In this abstract simulation, we assume units are always in range to attack.
        
        # Accuracy Check for Ranged Units
        if self.attack_type == "Ranged":
            if random.random() > self.get_current_accuracy():
                battle_log.append(f"{self.army_name}'s {self.name} misses {target.army_name}'s {target.name}.")
                self.action_cooldown = self.get_current_attack_speed()
                return

        # Calculate Damage
        damage = random.randint(self.damage_min, self.damage_max)
        
        # Handle Splash Damage
        if self.attack_type == "Splash":
            primary_damage_dealt = target.take_damage(damage, self.attack_type)
            battle_log.append(
                f"{self.army_name}'s {self.name} hits {target.army_name}'s {target.name} for {primary_damage_dealt} damage! "
                f"({target.health}/{target.max_health} HP)"
            )
            if not target.is_alive():
                self.add_kill()
                battle_log.append(f"  -> {target.army_name}'s {target.name} has been defeated!")

            # Find adjacent targets (simplified as random other targets for this text-based version)
            other_living_enemies = [u for u in enemy_army.units if u.is_alive() and u != target]
            splash_targets = random.sample(other_living_enemies, k=min(2, len(other_living_enemies)))
            for splash_target in splash_targets:
                splash_damage = int(damage * 0.5) # Splash deals 50% damage
                splash_damage_dealt = splash_target.take_damage(splash_damage, self.attack_type)
                battle_log.append(
                    f"  -> Splash damage hits {splash_target.army_name}'s {splash_target.name} for {splash_damage_dealt} damage! "
                    f"({splash_target.health}/{splash_target.max_health} HP)"
                )
                if not splash_target.is_alive():
                    self.add_kill()
                    battle_log.append(f"    -> {splash_target.army_name}'s {splash_target.name} has been defeated!")
        else:
            # Standard Attack
            damage_dealt = target.take_damage(damage, self.attack_type)
            battle_log.append(
                f"{self.army_name}'s {self.name} attacks {target.army_name}'s {target.name} for {damage_dealt} damage! "
                f"({target.health}/{target.max_health} HP)"
            )
            if not target.is_alive():
                self.add_kill()
                battle_log.append(f"  -> {target.army_name}'s {target.name} has been defeated!")

        self.action_cooldown = self.get_current_attack_speed()


class Army:
    """Represents a collection of units for one side."""
    def __init__(self, name):
        self.name = name
        self.units = [] # Initialize as an empty list

    def add_unit(self, unit):
        self.units.append(unit)

    def has_living_units(self):
        return any(unit.is_alive() for unit in self.units)
        
    def get_living_units(self):
        return [u for u in self.units if u.is_alive()]

class BattleSimulator:
    """The core engine that runs the battle simulation."""
    def __init__(self, army1, army2):
        self.army1 = army1
        self.army2 = army2

    def simulate_battle(self):
        """Runs the main battle loop until one army is defeated."""
        print("\n--- BATTLE BEGINS ---")
        print(f"{self.army1.name} vs. {self.army2.name}\n")
        time.sleep(1)

        initial_army1_count = len(self.army1.units)
        initial_army2_count = len(self.army2.units)
        round_num = 1

        while self.army1.has_living_units() and self.army2.has_living_units():
            print(f"\n--- Round {round_num} ---")
            battle_log = [] # Initialize battle log for the round
            
            # Create a turn order based on speed, with some randomness
            all_units = self.army1.get_living_units() + self.army2.get_living_units()
            turn_order = sorted(all_units, key=lambda u: u.movement_speed + random.uniform(-0.5, 0.5), reverse=True)

            # Process actions for each unit
            for unit in turn_order:
                if not unit.is_alive():
                    continue

                # Tick down cooldowns (simplified for this text version)
                unit.action_cooldown = max(0, unit.action_cooldown - 1.0)

                if unit.action_cooldown == 0:
                    # Correctly determine the enemy army
                    if unit in self.army1.units:
                        unit.perform_action(self.army2, battle_log)
                    else:
                        unit.perform_action(self.army1, battle_log)
            
            # Print the log for the round
            for entry in battle_log:
                wrapped_text = textwrap.fill(entry, width=80)
                print(wrapped_text)
                time.sleep(0.1) 
            
            # Calculate and display current survivors and casualties
            army1_survivors = len(self.army1.get_living_units())
            army2_survivors = len(self.army2.get_living_units())
            army1_deaths = initial_army1_count - army1_survivors
            army2_deaths = initial_army2_count - army2_survivors

            print(f"\n{self.army1.name}: {army1_survivors} survivors, {army1_deaths} casualties.")
            print(f"{self.army2.name}: {army2_survivors} survivors, {army2_deaths} casualties.")
            time.sleep(1)
            round_num += 1

        print("\n--- BATTLE ENDS ---")
        if self.army1.has_living_units():
            winner = self.army1
            loser = self.army2
        else:
            winner = self.army2
            loser = self.army1
        
        print(f"\nThe {winner.name} is victorious!")
        
        print("\n--- Final Report ---")
        print(f"\n{winner.name}'s Survivors:")
        for unit in sorted(winner.get_living_units(), key=lambda u: u.kills, reverse=True):
            print(f"  - {unit.name} ({unit.health}/{unit.max_health} HP) - Kills: {unit.kills}")

        print(f"\nDefeated Units from {loser.name}:")
        for unit in sorted(loser.units, key=lambda u: u.name):
             print(f"  - {unit.name} - Kills: {unit.kills}")

        # Return the allegiance of the winning army
        return winner.get_living_units()[0].allegiance


class Game:
    """Manages the overall game flow, menus, and setup."""
    def __init__(self, unit_data_file):
        self.unit_templates = self.load_unit_data(unit_data_file)
        if not self.unit_templates:
            print("Failed to load unit data. Exiting.")
            exit()
        self.light_wins = 0
        self.dark_wins = 0

    def load_unit_data(self, file_path):
        """Loads unit definitions from a JSON file."""
        try:
            with open(file_path, 'r') as f:
                return json.load(f)
        except FileNotFoundError:
            print(f"Error: {file_path} not found.")
            return None
        except json.JSONDecodeError:
            print(f"Error: Could not decode JSON from {file_path}. Check for formatting errors like trailing commas.")
            return None

    def run(self):
        """The main game loop."""
        while True:
            self.display_main_menu()
            choice = input("> ").strip().lower()
            if choice == '1':
                self.player_vs_computer()
            elif choice == '2':
                self.computer_vs_computer()
            elif choice == '3':
                print("Exiting the simulator. For the Light!")
                break
            else:
                print("Invalid choice. Please try again.")

    def display_main_menu(self):
        print("\n======================================")
        print("  Myth: Text Battle Simulator")
        print("======================================")
        print(f"  Score: Light {self.light_wins} - {self.dark_wins} Dark")
        print("--------------------------------------")
        print("1. Player vs. Computer")
        print("2. Computer vs. Computer")
        print("3. Quit")

    def select_army(self, army, point_limit):
        """Interface for the player to select their army."""
        points_spent = 0
        
        light_units = [u for u in self.unit_templates if u['Allegiance'] == 'Light']
        
        while True:
            print("\n--- Army Selection ---")
            print(f"Points Remaining: {point_limit - points_spent}")
            print("Current Army:")
            if not army.units:
                print("  (Empty)")
            else:
                unit_counts = {}
                for unit in army.units:
                    unit_counts[unit.name] = unit_counts.get(unit.name, 0) + 1
                for name, count in sorted(unit_counts.items()):
                    print(f"  - {count}x {name}")

            print("\nAvailable Light Units:")
            for i, template in enumerate(light_units):
                print(f"{i+1}. {template['Name']} ({template['PointCost']} pts)")
            
            print("\nEnter a number to add a unit, or type 'done' to finish.")
            choice = input("> ").strip().lower()

            if choice == 'done':
                if not army.units:
                    print("You must select at least one unit.")
                    continue
                break

            try:
                unit_index = int(choice) - 1
                if 0 <= unit_index < len(light_units):
                    template = light_units[unit_index]
                    if points_spent + template['PointCost'] <= point_limit:
                        army.add_unit(Unit(template, army.name))
                        points_spent += template['PointCost']
                        print(f"Added {template['Name']} to your army.")
                    else:
                        print("Not enough points!")
                else:
                    print("Invalid number.")
            except ValueError:
                print("Invalid input. Please enter a number or 'done'.")
        return army

    def create_computer_army(self, army, point_limit, allegiance):
        """AI for creating a computer-controlled army for a specific allegiance."""
        points_spent = 0
        choosable_units = [u for u in self.unit_templates if u['Allegiance'] == allegiance]
        
        if not choosable_units:
            print(f"Warning: No units found for allegiance '{allegiance}'.")
            return army

        # Simple AI: try to get a mix of units
        while points_spent < point_limit:
            available_choices = [u for u in choosable_units if u['PointCost'] <= (point_limit - points_spent)]
            if not available_choices:
                break
            
            template = random.choice(available_choices)
            army.add_unit(Unit(template, army.name))
            points_spent += template['PointCost']
        
        print(f"\nThe computer has assembled the {army.name}!")
        return army

    def player_vs_computer(self):
        """Sets up and runs a Player vs Computer battle."""
        point_limit = 100
        print(f"\nAssemble your army. You have {point_limit} points.")
        
        player_army = Army("Legion of Light")
        self.select_army(player_army, point_limit)
        
        computer_army = Army("Hordes of the Dark")
        self.create_computer_army(computer_army, point_limit, 'Dark')
        
        simulator = BattleSimulator(player_army, computer_army)
        winner_allegiance = simulator.simulate_battle()

        if winner_allegiance == 'Light':
            self.light_wins += 1
        else:
            self.dark_wins += 1
    
    def computer_vs_computer(self):
        """Sets up and runs a Computer vs Computer battle."""
        point_limit = 100
        print(f"\n--- Computer vs. Computer ---")
        print(f"Assembling two armies with {point_limit} points each.")

        light_army = Army("Legion of Light")
        self.create_computer_army(light_army, point_limit, 'Light')

        dark_army = Army("Hordes of the Dark")
        self.create_computer_army(dark_army, point_limit, 'Dark')

        # Pause to let the user see the generated armies
        print("\nPress Enter to begin the simulation...")
		
        while True:
            simulator = BattleSimulator(light_army, dark_army)
            winner_allegiance = simulator.simulate_battle()

            if winner_allegiance == 'Light':
                self.light_wins += 1
            else:
                self.dark_wins += 1


if __name__ == "__main__":
    # The name of the JSON file containing unit data.
    # This file must be in the same directory as the script.
    game = Game("units.json")
    game.run()

You may also like...

3 Responses

  1. filbet says:

    That immersive live casino experience is key – it really elevates the whole game! Seeing those high RTP rates (95.5%-98.2%!) at filbet app makes it even more appealing. Great insights into what players want!

  2. وی ایزوله ویسلی، پودری با 6 گرم BCAA و 14
    گرم EAA در هر سروینگ است که با روش میکروفیلتراسیون جریان متقاطع تولید
    می‌شود.

Leave a Reply

Your email address will not be published. Required fields are marked *