Narrative Scenes added

This commit is contained in:
Isaak Buslovich 2024-06-02 11:50:47 +02:00
parent fd647c2407
commit 30222c98ee
2 changed files with 687 additions and 443 deletions

687
main.py
View File

@ -1,17 +1,7 @@
"""
A simple business simulation game with a focus on market dynamics, crafting and trading.
Note: Requires 'rich' and 'json' libraries for functionality.
"""
import json import json
import random import random
from rich.console import Console import yaml
from rich.table import Table from blessed import Terminal
from rich.prompt import Prompt
from rich import box
from rich.panel import Panel
from rich.text import Text
crafting_recipes = { crafting_recipes = {
'Industrial Synthesis': {'input': {'Coal': 4, 'Copper': 4}, 'output': {'Conductor': 10}, 'turns': 3}, 'Industrial Synthesis': {'input': {'Coal': 4, 'Copper': 4}, 'output': {'Conductor': 10}, 'turns': 3},
@ -21,70 +11,7 @@ crafting_recipes = {
} }
def main():
"""Initializes the game environment, runs the game loop."""
console = Console()
competitors_ids = ["Player", "RationalAI", "RiskTakingAI"]
market = Market()
# Initialise the player
player = Company("Player", [cid for cid in competitors_ids if cid != "Player"], market)
# Initialise AI competitors
rational_ai = AICompany("RationalAI", competitors_ids, market, risk_tolerance=0.3)
risk_taking_ai = AICompany("RiskTakingAI", competitors_ids, market, risk_tolerance=0.7)
ai_competitors = [rational_ai, risk_taking_ai]
market.companies = {company.player_id: company for company in ai_competitors + [player]}
# Game loop
for turn in range(1, 27):
console.print(f"\n--- Turn {turn} ---\n", style="grey50")
market.inflation_rate += market.inflation_change if market.inflation_growing else -market.inflation_change
market.inflation_rate = max(0.0001, min(market.inflation_rate, 0.05))
market.gdp *= (1 + (market.inflation_rate / 20))
market.update_market()
market.print_market_events()
for company in [player] + ai_competitors:
company.update_crafting()
company.make_decision(market, ai_competitors)
print_ai_actions(ai_competitors)
final_scores = market.calculate_final_scores()
display_final_scores(console, final_scores, market)
def load_json(filename):
"""Loads and returns data from a JSON file specified by the filename."""
try:
with open(filename) as file:
return json.load(file)
except FileNotFoundError:
print(f"Error: The file {filename} was not found.")
exit(1)
class Market: class Market:
"""
Represents the game's market, managing product prices, stock ledger, and economic indicators.
Attributes:
current_turn (int): Counter for the game turn.
companies (dict): Stores company objects with their IDs.
products (dict): Current prices of products.
starting_prices (dict): Initial prices of products for comparison.
events (list): Potential market events affecting prices.
adjust_prices (function): Adjusts product prices based on trends.
event_effects (dict): Effects of market events on prices.
stock_ledger (dict): Tracks stock ownership.
inflation_rate (float): Inflation rate.
unemployment_rate (float): Unemployment rate.
gdp (float): Gross Domestic Product value.
The market is updated every turn.
"""
def __init__(self): def __init__(self):
self.current_turn = 0 self.current_turn = 0
self.companies = {} self.companies = {}
@ -111,22 +38,18 @@ class Market:
self.current_turn += 1 self.current_turn += 1
self.previous_prices = self.products.copy() self.previous_prices = self.products.copy()
# Update prices based on inflation and random fluctuations
for product in self.products: for product in self.products:
inflation_adjustment = self.inflation_rate inflation_adjustment = self.inflation_rate
random_fluctuation = random.uniform(-0.01, 0.01) # ±1% fluctuation random_fluctuation = random.uniform(-0.01, 0.01)
price_change_factor = 1 + inflation_adjustment + random_fluctuation price_change_factor = 1 + inflation_adjustment + random_fluctuation
self.products[product] *= price_change_factor self.products[product] *= price_change_factor
self.reset_trade_volumes() self.reset_trade_volumes()
# Procedural generation of market trends
self.trend_factor = self.generate_market_trend() self.trend_factor = self.generate_market_trend()
# Update economic indicators
self.update_economic_indicators() self.update_economic_indicators()
# Handle market events
self.handle_market_events() self.handle_market_events()
def update_prices(self): def update_prices(self):
@ -151,7 +74,6 @@ class Market:
def calculate_price_change(self, product): def calculate_price_change(self, product):
demand_factor = self.total_bought[product] - self.total_sold[product] demand_factor = self.total_bought[product] - self.total_sold[product]
# Here you can define how strongly demand affects the price, e.g., 0.05 as in your original code
return demand_factor * 0.05 return demand_factor * 0.05
def reset_trade_volumes(self): def reset_trade_volumes(self):
@ -163,36 +85,11 @@ class Market:
return max(0.5, min(self.trend_factor + trend_change, 1.5)) return max(0.5, min(self.trend_factor + trend_change, 1.5))
def update_economic_indicators(self): def update_economic_indicators(self):
"""Updates key economic indicators like inflation and unemployment rates."""
# Update inflation_rate
self.inflation_rate += self.inflation_change if self.inflation_growing else -self.inflation_change self.inflation_rate += self.inflation_change if self.inflation_growing else -self.inflation_change
self.inflation_rate = max(0.0001, min(self.inflation_rate, 0.05)) # Clamp the inflation_rate self.inflation_rate = max(0.0001, min(self.inflation_rate, 0.05))
self.gdp *= (1 + (self.inflation_rate / 20))
# Update GDP
self.gdp *= (1 + (self.inflation_rate / 2))
# Update unemployment_rate
self.unemployment_rate = min(max(self.unemployment_rate + random.uniform(-0.005, 0.005), 0), 1) self.unemployment_rate = min(max(self.unemployment_rate + random.uniform(-0.005, 0.005), 0), 1)
# Optional: Print statements for debugging
print(f"Inflation Rate: {self.inflation_rate}")
print(f"GDP: {self.gdp}")
print(f"Unemployment Rate: {self.unemployment_rate}")
def update_inflation_rate(self):
lower_bound = 0.0001
upper_bound = 0.049
if self.inflation_rate <= lower_bound:
self.inflation_growing = True
elif self.inflation_rate >= upper_bound:
self.inflation_growing = False
self.inflation_rate += self.inflation_change if self.inflation_growing else -self.inflation_change
def update_unemployment_rate(self):
fluctuation = random.uniform(-0.005, 0.005)
self.unemployment_rate = max(0, min(self.unemployment_rate + fluctuation, 1))
def handle_market_events(self): def handle_market_events(self):
event = random.choices(self.events, weights=[e["probability"] for e in self.events])[0] event = random.choices(self.events, weights=[e["probability"] for e in self.events])[0]
self.last_event_name = event["name"] self.last_event_name = event["name"]
@ -205,88 +102,32 @@ class Market:
random_resource = random.choice(['Coal', 'Copper']) random_resource = random.choice(['Coal', 'Copper'])
self.products[random_resource] *= 1.5 self.products[random_resource] *= 1.5
def trade_agreement_effect(self, price): def print_market_events(self, term):
"""Handles the effect of a new trade agreement event.""" event_info = f"{term.green}Last Market Event: {self.last_event_name}{term.normal}\n"
return price * 0.9
def innovation_breakthrough_effect(self, price):
"""Handles the effect of an innovation breakthrough event."""
return price * 0.8
def recession_effect(self, price):
"""Handles the effect of a recession event on product prices."""
return price * 0.7
def print_market_events(self):
"""
Prints the latest market events and key economic indicators in a formatted panel.
"""
# Prepare the console and panel text for printing
console = Console()
event_info = f"Last Market Event: {self.last_event_name}\n"
economic_indicators = ( economic_indicators = (
f"Inflation Rate: {self.inflation_rate * 100:.2f}%\n" f"{term.cyan}Inflation Rate: {self.inflation_rate * 100:.2f}%{term.normal}\n"
f"Unemployment Rate: {self.unemployment_rate * 100:.2f}%\n" f"{term.cyan}Unemployment Rate: {self.unemployment_rate * 100:.2f}%{term.normal}\n"
f"GDP: {self.gdp:.2f}" f"{term.cyan}GDP: {self.gdp:.2f}{term.normal}"
) )
print(term.move_y(term.height // 4))
# Create a formatted panel text print(term.center(event_info + economic_indicators))
panel_text = Text(event_info + economic_indicators)
# Print the panel with styling
console.print(Panel(panel_text, title="[bold]Market Events and Indicators", border_style="grey50"))
def update_stock_ledger(self, company_id, owner_id, amount): def update_stock_ledger(self, company_id, owner_id, amount):
"""Updates the stock ledger for a given company and owner based on the transaction amount."""
self.stock_ledger[company_id, owner_id] = self.stock_ledger.get((company_id, owner_id), 0) + amount self.stock_ledger[company_id, owner_id] = self.stock_ledger.get((company_id, owner_id), 0) + amount
def get_stock_ownership(self, company_id, owner_id): def get_stock_ownership(self, company_id, owner_id):
"""Returns the number of stocks owned by a given owner for a specified company."""
return self.stock_ledger.get((company_id, owner_id), 0) return self.stock_ledger.get((company_id, owner_id), 0)
def get_stock_price(self, company_id): def get_stock_price(self, company_id):
"""Calculates and returns the current stock price for a specified company."""
return round(self.companies[company_id].value / 100.0, 2) return round(self.companies[company_id].value / 100.0, 2)
def update_market(self):
self.current_turn += 1
self.previous_prices = self.products.copy()
# Update prices based on supply and demand
for product in self.products:
supply_chain_impact = self.simulate_supply_chain_impact(product)
demand_factor = self.total_bought[product] - self.total_sold[product]
self.products[product] *= (1 + demand_factor * 0.05) * supply_chain_impact
self.reset_trade_volumes()
# Procedural generation of market trends
self.trend_factor = self.generate_market_trend()
# Update economic indicators
self.update_economic_indicators()
# Handle market events
self.handle_market_events()
def simulate_supply_chain_impact(self, product): def simulate_supply_chain_impact(self, product):
return random.uniform(0.9, 1.1) return random.uniform(0.9, 1.1)
def generate_market_trend(self):
trend_change = random.uniform(-0.02, 0.02)
new_trend = self.trend_factor + trend_change
return max(0.5, min(new_trend, 1.5))
def reset_trade_volumes(self):
for product in self.total_bought.keys():
self.total_bought[product] = 0
self.total_sold[product] = 0
def record_trade(self, value): def record_trade(self, value):
self.trade_volume += value self.trade_volume += value
def adjust_prices(self): def adjust_prices(self):
"""Adjusts product prices in the market based on inflation and random fluctuations."""
for product, price in self.products.items(): for product, price in self.products.items():
inflation_adjustment = price * self.inflation_rate inflation_adjustment = price * self.inflation_rate
fluctuation = random.uniform(-0.03, 0.03) fluctuation = random.uniform(-0.03, 0.03)
@ -294,33 +135,11 @@ class Market:
return self.products return self.products
def handle_competitor_event(self, effect): def handle_competitor_event(self, effect):
"""Handles market events related to competitors, adjusting product prices accordingly."""
adjustment = float(random.randint(1, 3)) adjustment = float(random.randint(1, 3))
self.products = {k: max(1.0, v - adjustment) if effect == "new_competitor" else v + adjustment for k, v in self.products = {k: max(1.0, v - adjustment) if effect == "new_competitor" else v + adjustment for k, v in
self.products.items()} self.products.items()}
def update_economic_indicators(self):
"""Updates key economic indicators like inflation and unemployment rates."""
# Check bounds and change state if necessary
if self.inflation_rate <= 0.0001: # Lower bound
self.inflation_growing = True
self.inflation_change = random.uniform(0.0001, 0.001) # Reset change rate
elif self.inflation_rate >= 0.049: # Upper bound
self.inflation_growing = False
self.inflation_change = random.uniform(0.0001, 0.001) # Reset change rate
# Adjust inflation rate based on the current state
if self.inflation_growing:
self.inflation_rate += self.inflation_change
else:
self.inflation_rate -= self.inflation_change
# Unemployment rate adjustment with random fluctuation
self.unemployment_rate = min(max(self.unemployment_rate + random.uniform(-0.005, 0.005), 0), 1)
def calculate_final_scores(self): def calculate_final_scores(self):
"""Calculates and returns final scores for each company based on value and stock ownership."""
final_scores = {} final_scores = {}
for company_id, company in self.companies.items(): for company_id, company in self.companies.items():
final_score = company.value final_score = company.value
@ -342,21 +161,6 @@ class Market:
class Company: class Company:
"""
Base class for a company in the game, handling inventory, stock, and financial transactions.
Attributes:
player_id (str): Unique identifier for the company.
cash (float): Available cash for transactions.
inventory (dict): Current inventory of products.
crafting_queue (list): Queue of products being crafted.
own_stock_ownership (dict): Ownership percentage of own stocks.
stock_holdings (dict): Holdings of other companies' stocks.
total_shares (int): Total shares available in the company.
_market (Market): Reference to the game's market.
_debug (bool): Flag for enabling debug mode.
"""
def __init__(self, player_id, competitors_ids, market=None, debug=False): def __init__(self, player_id, competitors_ids, market=None, debug=False):
self.player_id = player_id self.player_id = player_id
self.cash = 500.0 self.cash = 500.0
@ -371,11 +175,9 @@ class Company:
@property @property
def value(self): def value(self):
"""Calculates the total value of the company, combining cash and the market value of its inventory."""
return self.cash + sum(self.inventory[product] * price for product, price in self._market.products.items()) return self.cash + sum(self.inventory[product] * price for product, price in self._market.products.items())
def craft_product(self, recipe_key): def craft_product(self, recipe_key):
"""Processes crafting of a product based on the chosen recipe."""
if self._debug: if self._debug:
print(f"Inventory before crafting: {self.inventory}") print(f"Inventory before crafting: {self.inventory}")
recipe = crafting_recipes[recipe_key] recipe = crafting_recipes[recipe_key]
@ -389,7 +191,6 @@ class Company:
print(f"Inventory after crafting: {self.inventory}") print(f"Inventory after crafting: {self.inventory}")
def _update_inventory(self, items, decrease=False): def _update_inventory(self, items, decrease=False):
"""Updates the inventory based on the given items."""
if self._debug: if self._debug:
print(f"Inventory before update: {self.inventory}") print(f"Inventory before update: {self.inventory}")
for product, quantity in items.items(): for product, quantity in items.items():
@ -401,7 +202,6 @@ class Company:
print(f"Inventory after update: {self.inventory}") print(f"Inventory after update: {self.inventory}")
def update_crafting(self): def update_crafting(self):
"""Updates the crafting queue, completing orders as their turns conclude."""
if self._debug: if self._debug:
print(f"Crafting queue before update: {self.crafting_queue}") print(f"Crafting queue before update: {self.crafting_queue}")
completed_orders = [] completed_orders = []
@ -429,34 +229,28 @@ class Company:
if self.cash >= total_cost: if self.cash >= total_cost:
self.cash -= total_cost self.cash -= total_cost
self.inventory[product] += quantity self.inventory[product] += quantity
market.total_bought[product] += quantity # Record the purchase in the market market.total_bought[product] += quantity
market.record_trade(total_cost) # Update the market's trade volume market.record_trade(total_cost)
else: else:
print("Insufficient funds to complete purchase.") print("Insufficient funds to complete purchase.")
else: else:
if self.inventory[product] >= quantity: if self.inventory[product] >= quantity:
self.cash += total_cost self.cash += total_cost
self.inventory[product] -= quantity self.inventory[product] -= quantity
market.total_sold[product] += quantity # Record the sale in the market market.total_sold[product] += quantity
market.record_trade(total_cost) # Update the market's trade volume market.record_trade(total_cost)
else: else:
print("Insufficient inventory to complete sale.") print("Insufficient inventory to complete sale.")
# Update market prices after trading market.update_prices()
market.update_prices() # This call ensures prices are updated with constraints
def crafting_decision(self): def crafting_decision(self, term):
"""Displays crafting options and handles the user's crafting choice.""" print(term.home + term.clear + term.move_y(term.height // 2))
print("\nCrafting Decision")
recipe_keys = list(crafting_recipes.keys()) recipe_keys = list(crafting_recipes.keys())
print("\nAvailable Recipes:") recipe_choice = self.display_menu("Choose a recipe to craft:", recipe_keys, term)
for idx, recipe in enumerate(recipe_keys, 1): self.craft_product(recipe_keys[recipe_choice])
print(f" {idx}: {recipe}")
recipe_choice = self.get_user_choice(len(recipe_keys), "Choose a recipe to craft: ")
self.craft_product(recipe_keys[recipe_choice - 1])
def trade_stock(self, action, market, company_id, amount, is_ai=False): def trade_stock(self, action, market, company_id, amount, is_ai=False):
"""Executes a stock trade action, buying or selling as specified."""
if company_id not in market.companies and company_id != self.player_id: if company_id not in market.companies and company_id != self.player_id:
return "Company not found in the market." return "Company not found in the market."
@ -471,11 +265,9 @@ class Company:
return "Invalid stock action." return "Invalid stock action."
def _buy_stock(self, company_id, amount): def _buy_stock(self, company_id, amount):
# Calculate the total number of shares currently owned
total_shares_owned = sum(self._market.companies[company_id].own_stock_ownership.values()) total_shares_owned = sum(self._market.companies[company_id].own_stock_ownership.values())
available_shares = self.total_shares - total_shares_owned available_shares = self.total_shares - total_shares_owned
# Determine the maximum shares that can be bought based on available cash and available shares
max_affordable_shares = int(self.cash / self._market.get_stock_price(company_id)) max_affordable_shares = int(self.cash / self._market.get_stock_price(company_id))
amount = min(amount, available_shares, max_affordable_shares) amount = min(amount, available_shares, max_affordable_shares)
@ -490,7 +282,6 @@ class Company:
if company_id != self.player_id: if company_id != self.player_id:
self.stock_holdings[company_id] += amount self.stock_holdings[company_id] += amount
else: else:
# Update own_stock_ownership when buying own shares
self.own_stock_ownership[self.player_id] += amount self.own_stock_ownership[self.player_id] += amount
return f"Bought {amount} stocks of {company_id}." return f"Bought {amount} stocks of {company_id}."
@ -499,174 +290,96 @@ class Company:
if not is_ai: if not is_ai:
if self.stock_holdings[company_id] < amount: if self.stock_holdings[company_id] < amount:
return "Not enough stocks to sell." return "Not enough stocks to sell."
# Update buyer's stock_holdings for non-AI (like player)
self.stock_holdings[company_id] -= amount self.stock_holdings[company_id] -= amount
else: else:
if self.own_stock_ownership[company_id] < amount: if self.own_stock_ownership[company_id] < amount:
return "Not enough stocks to sell." return "Not enough stocks to sell."
# Update own_stock_ownership for AI
self.own_stock_ownership[company_id] -= amount self.own_stock_ownership[company_id] -= amount
self.cash += total_value self.cash += total_value
self._market.update_stock_ledger(company_id, self.player_id, -amount) self._market.update_stock_ledger(company_id, self.player_id, -amount)
# If an AI company is selling its own shares, update the ownership for all shareholders
if is_ai and company_id == self.player_id: if is_ai and company_id == self.player_id:
for shareholder in self._market.companies[company_id].own_stock_ownership.keys(): for shareholder in self._market.companies[company_id].own_stock_ownership.keys():
self._market.companies[company_id].own_stock_ownership[shareholder] -= amount * \ self._market.companies[company_id].own_stock_ownership[shareholder] -= amount * (
(self._market.companies[ self._market.companies[company_id].own_stock_ownership[shareholder] / self.total_shares)
company_id].own_stock_ownership[
shareholder] / self.total_shares)
return f"Sold {amount} stocks of {company_id}." return f"Sold {amount} stocks of {company_id}."
def _calculate_available_shares(self): def display_menu(self, prompt, options, term):
"""Calculates the number of available shares for a given company.""" selected_option = 0
total_owned = sum(self.stock_holdings.values()) + sum(self.own_stock_ownership.values())
return self.total_shares - total_owned
def _get_stock_ownership(self, company_id): with term.cbreak(), term.hidden_cursor():
"""Retrieves the stock ownership amount for a given company.""" while True:
if company_id == self.player_id: print(term.home + term.clear + term.move_y(term.height // 2))
return self.own_stock_ownership[self.player_id] print(term.center(prompt))
return self.stock_holdings.get(company_id, 0) for i, option in enumerate(options):
prefix = '-> ' if i == selected_option else ' '
print(term.move_down(2) + term.center(f"{prefix}{option}"))
key = term.inkey()
if key.name == 'KEY_UP':
selected_option = (selected_option - 1) % len(options)
elif key.name == 'KEY_DOWN':
selected_option = (selected_option + 1) % len(options)
elif key.name == 'KEY_ENTER':
return selected_option
def _update_stock_ownership(self, company_id, amount, total_value, buying): def make_decision(self, market, competitors, term):
"""Updates the stock ownership details after a buy or sell action.""" status_info = (
if company_id == self.player_id: f"\n{term.bold}{self.player_id}'s Turn - Turn {market.current_turn}{term.normal}\n\n"
if buying: f"Cash: {term.yellow}{self.cash:.2f}{term.normal}\n"
self.own_stock_ownership[self.player_id] += amount f"Inventory: {', '.join([f'{item}: {quantity}' for item, quantity in self.inventory.items()])}\n"
else: f"Market Prices: {', '.join([f'{product}: {term.green if market.products[product] > market.previous_prices[product] else term.red}{market.products[product]:.2f}{term.normal}{"" if market.products[product] > market.previous_prices[product] else ""}' for product in market.products])}\n"
self.own_stock_ownership[self.player_id] -= amount f"Your Shareholders: {', '.join([f'{company}: {ownership} shares' for company, ownership in self.own_stock_ownership.items()])}\n"
else: f"Your Investments: {', '.join([f'{company}: {holding} shares' for company, holding in self.stock_holdings.items() if holding > 0])}"
if buying: )
self.stock_holdings[company_id] += amount
else:
self.stock_holdings[company_id] -= amount
self.cash += -total_value if buying else total_value
def make_decision(self, market, competitors): actions = [
console = Console() "Trade Products 📦",
status_table = Table(title=f"\n[bold cyan]{self.player_id}'s Turn - Turn {market.current_turn}", "Craft 🛠️",
box=box.ROUNDED) "Trade Stocks 📈",
"Skip Turn ⏭️"
]
# Cash Row selected_action = self.display_menu(status_info + "\n\nChoose your action:", actions, term)
status_table.add_column("Category", style="bold cyan")
status_table.add_column("Details")
status_table.add_row("Cash", f"[bold blue]{self.cash:.2f}")
# Inventory Row if selected_action == 0:
inventory_display = ', '.join([f"[bold]{item}: {quantity}" for item, quantity in self.inventory.items()]) self.trade_products_decision(market, term)
status_table.add_row("Inventory", inventory_display) elif selected_action == 1:
self.crafting_decision(term)
elif selected_action == 2:
stock_actions = ["Buy 📈", "Sell 📉"]
stock_action_choice = self.display_menu("Choose stock action:", stock_actions, term)
self.trade_stocks_decision(stock_action_choice.lower(), market, competitors, term)
elif selected_action == 3:
pass
# Market Prices Row with Color Coding and Emojis def trade_products_decision(self, market, term):
price_info = []
for product, price in market.products.items():
price_change = price - market.previous_prices.get(product, price)
if price_change > 0:
price_info.append(f"[green]{product}: {price:.2f} € :arrow_up_small:") # Green color and up emoji
elif price_change < 0:
price_info.append(f"[red]{product}: {price:.2f} € :arrow_down_small:") # Red color and down emoji
else:
price_info.append(f"{product}: {price:.2f}") # Default color (no change)
status_table.add_row("Market Prices", ', '.join(price_info))
# Shareholders Row
shareholders = ', '.join(
[f"[bold]{company}[/]: {ownership} shares" for company, ownership in self.own_stock_ownership.items()])
status_table.add_row("Your Shareholders", shareholders)
# Investments Row
investments = ', '.join(
[f"[bold]{company}[/]: {holding} shares" for company, holding in self.stock_holdings.items() if
holding > 0])
status_table.add_row("Your Investments", investments)
console.print(status_table)
# Action Choices
actions = {
"1": "Trade Products",
"2": "Craft",
"3": "Trade Stocks",
"4": "Skip Turn"
}
choices_display = "\n".join([f"{key}: {value}" for key, value in actions.items()])
console.print(f"Available Actions:\n{choices_display}", style="bold")
# Action Selection
action_choice = Prompt.ask("Choose your action", default="4")
selected_action = actions.get(action_choice, None)
if selected_action == "Trade Products":
self.trade_products_decision(market)
elif selected_action == "Craft":
self.crafting_decision()
elif selected_action == "Trade Stocks":
stock_actions = ["Buy", "Sell"]
stock_action_choice = Prompt.ask("Choose stock action", choices=stock_actions, default=stock_actions[0])
self.trade_stocks_decision(stock_action_choice.lower(), market, competitors)
elif selected_action == "Skip Turn":
pass # Skip turn
else:
console.print("[bold red]Invalid choice. Please enter a valid option.")
def trade_products_decision(self, market):
"""Handles the decision-making process for trading products."""
print("\nProduct Trading Decision")
products = list(market.products.keys()) products = list(market.products.keys())
print("\nAvailable Products:") product_choice = self.display_menu("Choose a product to trade:", products, term)
for idx, product in enumerate(products, 1): product = products[product_choice]
print(f" {idx}: {product} - Price: {market.products[product]:.2f}")
product_choice = self.get_user_choice(len(products), "Choose a product to trade: ")
product = products[product_choice - 1]
quantity = self.get_valid_input("Enter the quantity to trade: ", int, "Quantity must be positive.", quantity = self.get_valid_input("Enter the quantity to trade: ", int, "Quantity must be positive.",
lambda x: x > 0) lambda x: x > 0)
self.get_user_choice(2, "Choose trade type (1: Buy, 2: Sell): ") trade_types = ["Buy 📈", "Sell 📉"]
self.trade_product(market, product, quantity) trade_choice = self.display_menu("Choose trade type:", trade_types, term)
buying = trade_choice == 0
def trade_stocks_decision(self, action, market, competitors): self.trade_product(market, product, quantity, buying=buying)
"""Facilitates the decision-making process for stock trading actions."""
print("\nStock Trading Decision")
if action == 'buy':
print("Available companies to buy stocks from:")
elif action == 'sell':
print("Your stock holdings:")
def trade_stocks_decision(self, action, market, competitors, term):
companies = competitors + [self] companies = competitors + [self]
company_names = [company.player_id for company in companies]
for idx, company in enumerate(companies, 1): company_choice = self.display_menu("Enter the company number to trade stocks:", company_names, term)
company_id = company.player_id company_id = company_names[company_choice]
stock_info = f" {idx}: {company_id} - Current stock price: {market.get_stock_price(company_id)}"
if action == 'sell' and self.stock_holdings.get(company_id, 0) > 0:
stock_info += f", Owned: {self.stock_holdings[company_id]}"
print(stock_info)
company_choice = self.get_user_choice(len(companies), "Enter the company number to trade stocks: ")
company_id = companies[company_choice - 1].player_id
amount = self.get_valid_input("Enter the amount of stocks to trade: ", int, "Stock amount must be positive.", amount = self.get_valid_input("Enter the amount of stocks to trade: ", int, "Stock amount must be positive.",
lambda x: x > 0) lambda x: x > 0)
self.trade_stock(action, market, company_id, amount) self.trade_stock(action, market, company_id, amount)
@staticmethod
def get_user_choice(num_options, prompt):
"""Prompts the user for a choice and validates the input."""
choice = 0
while choice < 1 or choice > num_options:
try:
choice = int(input(prompt))
if choice < 1 or choice > num_options:
raise ValueError
except ValueError:
print(f"Please enter a number between 1 and {num_options}.")
return choice
@staticmethod @staticmethod
def get_valid_input(prompt, input_type, error_message, validation_func=lambda x: True): def get_valid_input(prompt, input_type, error_message, validation_func=lambda x: True):
"""Requests and validates user input based on specified criteria."""
while True: while True:
try: try:
value = input_type(input(prompt)) value = input_type(input(prompt))
@ -676,23 +389,8 @@ class Company:
except ValueError: except ValueError:
print(error_message) print(error_message)
def is_market_boom(self):
"""Checks if the market is booming."""
return all(price > 20 for price in self._market.products.values())
class AICompany(Company): class AICompany(Company):
"""
AI Company. Inherits from the Company class and adds AI-specific decision-making based on risk tolerance.
Attributes:
risk_tolerance (float): A value representing the AI's willingness to take risks, influencing its decisions.
actions_history (list): Records the history of actions taken by the AI.
average_prices (dict): Tracks the average market prices of products for strategic decision-making.
Methods provide the AI's logic for crafting, trading, stock transactions, and handling market events.
"""
def __init__(self, player_id, competitors_ids, market, risk_tolerance): def __init__(self, player_id, competitors_ids, market, risk_tolerance):
super().__init__(player_id, competitors_ids, market) super().__init__(player_id, competitors_ids, market)
self.risk_tolerance = risk_tolerance self.risk_tolerance = risk_tolerance
@ -700,21 +398,17 @@ class AICompany(Company):
self.average_prices = {product: market.products[product] for product in market.products} self.average_prices = {product: market.products[product] for product in market.products}
def update_average_prices(self): def update_average_prices(self):
"""Updates the average prices of products in the market for AI decision-making purposes."""
self.average_prices = {product: (self.average_prices[product] * ( self.average_prices = {product: (self.average_prices[product] * (
self._market.current_turn - 1) + price) / self._market.current_turn self._market.current_turn - 1) + price) / self._market.current_turn
for product, price in self._market.products.items()} for product, price in self._market.products.items()}
def make_decision(self, market, competitors): def make_decision(self, market, competitors, term):
if self.risk_tolerance > 0.5: # High-Risk AI if self.risk_tolerance > 0.5:
self.high_risk_decision(market) self.high_risk_decision(market, term)
else: # Low-Risk AI else:
self.low_risk_decision(market) self.low_risk_decision(market, term)
def low_risk_decision(self, market): def low_risk_decision(self, market, term):
"""
Defines the decision-making process for a low-risk AI player.
"""
if market.current_turn == 1: if market.current_turn == 1:
self.buy_product('Coal', self.cash / 3) self.buy_product('Coal', self.cash / 3)
elif market.current_turn == 2: elif market.current_turn == 2:
@ -722,10 +416,7 @@ class AICompany(Company):
elif market.current_turn >= 3: elif market.current_turn >= 3:
self.buy_and_craft() self.buy_and_craft()
def high_risk_decision(self, market): def high_risk_decision(self, market, term):
"""
Defines the decision-making process for a high-risk AI player.
"""
if market.current_turn == 1: if market.current_turn == 1:
self.sell_own_shares(market) self.sell_own_shares(market)
self.buy_product('Coal', self.cash / 2) self.buy_product('Coal', self.cash / 2)
@ -739,9 +430,6 @@ class AICompany(Company):
self.buy_stocks_strategy() self.buy_stocks_strategy()
def buy_product(self, product, budget): def buy_product(self, product, budget):
"""
Buys a specific quantity of a product for the AI company.
"""
quantity = int(budget // self._market.products[product]) quantity = int(budget // self._market.products[product])
if quantity > 0: if quantity > 0:
self.trade_product(self._market, product, quantity) self.trade_product(self._market, product, quantity)
@ -769,33 +457,21 @@ class AICompany(Company):
return return
def sell_own_shares(self, market): def sell_own_shares(self, market):
""" amount_to_sell = int(self.own_stock_ownership[self.player_id] * 0.25)
Sells a portion of the AI company's own shares.
"""
amount_to_sell = int(self.own_stock_ownership[self.player_id] * 0.25) # Sell 25% of own shares
if amount_to_sell > 0: if amount_to_sell > 0:
self.trade_stock('sell', market, self.player_id, amount_to_sell, is_ai=True) self.trade_stock('sell', market, self.player_id, amount_to_sell, is_ai=True)
action = f"Sold {amount_to_sell} of own shares" action = f"Sold {amount_to_sell} of own shares"
self.actions_history.append(action) self.actions_history.append(action)
def should_craft(self): def should_craft(self):
"""
Determines if the AI should craft products based on inventory and market conditions.
"""
return all( return all(
self.inventory[product] >= qty for product, qty in crafting_recipes['Manual Synthesis']['input'].items()) self.inventory[product] >= qty for product, qty in crafting_recipes['Manual Synthesis']['input'].items())
def should_sell_products(self, market): def should_sell_products(self, market):
"""
Decides if the AI should sell products based on market prices.
"""
return any(market.products[product] >= 2 * self.average_prices[product] for product in self.inventory if return any(market.products[product] >= 2 * self.average_prices[product] for product in self.inventory if
self.inventory[product] > 0) self.inventory[product] > 0)
def sell_high_value_products(self, market): def sell_high_value_products(self, market):
"""
Decides if the AI should sell products based on market prices.
"""
for product, quantity in self.inventory.items(): for product, quantity in self.inventory.items():
if quantity > 0 and market.products[product] >= 2 * self.average_prices[product]: if quantity > 0 and market.products[product] >= 2 * self.average_prices[product]:
self.trade_product(market, product, quantity, buying=False) self.trade_product(market, product, quantity, buying=False)
@ -803,9 +479,6 @@ class AICompany(Company):
self.actions_history.append(action) self.actions_history.append(action)
def buy_and_craft(self): def buy_and_craft(self):
"""
Executes buying of resources and crafting of products for the AI.
"""
chosen_recipe = crafting_recipes['Manual Synthesis'] chosen_recipe = crafting_recipes['Manual Synthesis']
if all(self.inventory[product] >= qty for product, qty in chosen_recipe['input'].items()): if all(self.inventory[product] >= qty for product, qty in chosen_recipe['input'].items()):
self.craft_product('Manual Synthesis') self.craft_product('Manual Synthesis')
@ -816,48 +489,176 @@ class AICompany(Company):
print("Not enough resources to craft using Manual Synthesis") print("Not enough resources to craft using Manual Synthesis")
def print_ai_actions(ai_competitors): def apply_effects(player, effects, narrative_game):
"""Displays the actions history, current cash, inventory, and stock information of AI competitors.""" for effect in effects:
console = Console() for key, value in effect.items():
for ai in ai_competitors: if key == 'employee_morale':
panel_text = Text() player.employee_morale += value
inventory_text = ', '.join([f"{product}: {quantity}" for product, quantity in ai.inventory.items()]) elif key == 'company_budget':
player.cash += value
elif key == 'company_reputation':
player.reputation += value
elif key == 'set_flag':
player.flags[value] = True
elif key == 'set_variable':
if value in narrative_game.scenes[narrative_game.current_scene].get('Names', {}):
narrative_game.set_random_name(
narrative_game.scenes[narrative_game.current_scene]['Names'][value], value
)
else:
narrative_game.variables[value] = value
# List all actions def handle_narrative_event(player, narrative_game):
for idx, action in enumerate(ai.actions_history, 1): # Iterate through the scenes to find the applicable one
panel_text.append(f"{idx}. Action: {action}\n", style="grey50") for scene_name, scene in narrative_game.scenes.items():
if all(player.flags.get(cond, 0) == value for cond, value in scene.get('Conditions', {}).items()):
narrative_game.current_scene = scene_name
break
# Append current cash and inventory to the text # Ensure variables are set before displaying content
panel_text.append(f"\nCurrent Cash: {ai.cash:.2f}\n", style="bold blue") scene = narrative_game.scenes[narrative_game.current_scene]
panel_text.append(f"Inventory: {inventory_text}\n", style="bold cyan") for option in scene['Links']:
for effect in option['Effects']:
if 'set_variable' in effect:
variable_name = effect['set_variable']
if variable_name in scene.get('Names', {}):
narrative_game.set_random_name(scene['Names'][variable_name], variable_name)
# Display Shareholders and Investments # Display the content with variables replaced
shareholders_text = ', '.join( narrative_game.display_text(narrative_game.scenes[narrative_game.current_scene]['Content'])
[f"{company}: {ownership} shares" for company, ownership in ai.own_stock_ownership.items()])
investments_text = ', '.join(
[f"{company}: {holding} shares" for company, holding in ai.stock_holdings.items() if holding > 0])
panel_text.append(f"Shareholders: {shareholders_text}\n", style="bold green") # Handle user input and apply effects
panel_text.append(f"Investments: {investments_text}", style="bold magenta") while True:
scene = narrative_game.scenes[narrative_game.current_scene]
# Display in a panel if not scene['Links']:
console.print(Panel(panel_text, title=f"[bold]{ai.player_id}'s Status", border_style="grey50")) narrative_game.display_text("The End. Thank you for playing!")
break
choice = narrative_game.handle_input(scene['Links'])
selected_option = scene['Links'][choice]
apply_effects(player, selected_option['Effects'], narrative_game)
narrative_game.current_scene = selected_option['Target']
break
def display_final_scores(console, final_scores, market): class Player(Company):
"""Displays the final scores in a styled table.""" def __init__(self, player_id, competitors_ids, market):
score_table = Table(header_style="bold cyan", box=box.DOUBLE_EDGE) super().__init__(player_id, competitors_ids, market)
score_table.add_column("Company", style="bold") self.flags = {"daughterevent": 0}
score_table.add_column("Final Score", justify="right") self.variables = {}
score_table.add_column("Majority Owner", style="bold")
score_table.add_column("Ownership Percentage", justify="right", style="dim")
class TUIGame:
def __init__(self, config_path):
self.term = Terminal()
self.load_config(config_path)
self.scenes = {scene['PassageName']: scene for scene in self.config}
self.current_scene = None
self.variables = {}
def load_config(self, path):
with open(path, 'r') as file:
self.config = yaml.safe_load(file)
def display_text(self, text):
text = self.replace_variables(text)
print(self.term.home + self.term.clear + self.term.move_y(self.term.height // 2))
for line in text.split('\n'):
print(self.term.center(line))
print(self.term.move_down(2) + self.term.center("Press Enter to continue..."))
with self.term.cbreak(), self.term.hidden_cursor():
while True:
key = self.term.inkey()
if key.name == 'KEY_ENTER':
break
def display_choices(self, scene, selected_choice):
content = self.replace_variables(scene['Content'])
print(self.term.home + self.term.clear + self.term.move_y(self.term.height // 2))
print(self.term.center(content))
for i, link in enumerate(scene['Links']):
prefix = '-> ' if i == selected_choice else ' '
description = link.get('EffectDescription', '')
option_text = f"{prefix}{link['Option']}"
if i == selected_choice:
print(self.term.move_down(2) + self.term.center(self.term.bold(option_text)))
print(self.term.center(self.term.gray(description)))
else:
print(self.term.move_down(2) + self.term.center(option_text))
def handle_input(self, choices):
selected_choice = 0
with self.term.cbreak(), self.term.hidden_cursor():
while True:
self.display_choices(self.scenes[self.current_scene], selected_choice)
key = self.term.inkey()
if key.name == 'KEY_UP':
selected_choice = (selected_choice - 1) % len(choices)
elif key.name == 'KEY_DOWN':
selected_choice = (selected_choice + 1) % len(choices)
elif key.name == 'KEY_ENTER':
return selected_choice
def replace_variables(self, text):
for var, value in self.variables.items():
text = text.replace(f'{{{{ {var} }}}}', value)
return text
def set_random_name(self, names_list, variable_name):
name = random.choice(names_list)
self.variables[variable_name] = name
def main():
term = Terminal()
competitors_ids = ["Player", "RationalAI", "RiskTakingAI"]
market = Market()
player = Player("Player", [cid for cid in competitors_ids if cid != "Player"], market)
player.employee_morale = 0
player.reputation = 0
rational_ai = AICompany("RationalAI", competitors_ids, market, risk_tolerance=0.3)
risk_taking_ai = AICompany("RiskTakingAI", competitors_ids, market, risk_tolerance=0.7)
ai_competitors = [rational_ai, risk_taking_ai]
market.companies = {company.player_id: company for company in ai_competitors + [player]}
narrative_game = TUIGame('narrative_scenes.yml')
for turn in range(1, 27):
print(term.home + term.clear + term.move_y(term.height // 2))
print(term.center(f"\n--- Turn {turn} ---\n"))
market.update_market()
market.print_market_events(term)
for company in [player] + ai_competitors:
company.update_crafting()
company.make_decision(market, ai_competitors, term)
handle_narrative_event(player, narrative_game)
final_scores = market.calculate_final_scores()
print_final_scores(term, final_scores, market)
def print_final_scores(term, final_scores, market):
score_table = (
f"\n{'Company':<15} {'Final Score':<15} {'Majority Owner':<20} {'Ownership Percentage':<20}\n"
f"{'-'*70}\n"
)
for company_id, data in sorted(final_scores.items(), key=lambda item: item[1]['score'], reverse=True): for company_id, data in sorted(final_scores.items(), key=lambda item: item[1]['score'], reverse=True):
ownership_percentage = f"{data['score'] / market.companies[company_id].value * 100:.2f}%" ownership_percentage = f"{data['score'] / market.companies[company_id].value * 100:.2f}%"
score_table.add_row(company_id, f"{data['score']:.0f}", data['majority_owner'], ownership_percentage) score_table += f"{company_id:<15} {data['score']:<15.0f} {data['majority_owner']:<20} {ownership_percentage:<20}\n"
print(term.home + term.clear + term.move_y(term.height // 2))
console.print(score_table) print(term.center(score_table))
def load_json(filename):
try:
with open(filename) as file:
return json.load(file)
except FileNotFoundError:
print(f"Error: The file {filename} was not found.")
exit(1)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

443
narrative_scenes.yml Normal file
View File

@ -0,0 +1,443 @@
- PassageName: EmployeeRequest
Content: >-
After a long day at work, you find yourself chatting with one of your employees. {{ dad_name }} seems eager but anxious as they share a personal request.
"My daughter just graduated and is looking for a job. She's hardworking and eager to learn. I was wondering if you could consider hiring her?"
You ponder the request, knowing that your decision could impact both the employee's morale and the company's dynamics.
Conditions:
daughterevent: 0
Names:
daughter_name:
- Emily
- Sarah
- Jessica
- Rachel
- Laura
dad_name:
- John
- Michael
- David
- Robert
- James
Links:
- Option: "Sure, Ill hire her."
Target: Hired
Effects:
- employee_morale: +10
- company_budget: -100
- set_flag: daughterevent
- set_flag: daughter_hired
- set_variable: daughter_name
- set_variable: dad_name
EffectDescription: "This will boost the employee's morale but will cost the company some money."
- Option: "Sorry, we dont have any openings."
Target: NoHiring
Effects:
- employee_morale: -5
- set_flag: daughterevent
- set_variable: dad_name
EffectDescription: "This might disappoint the employee and affect their morale."
- Option: "Ill consider it, but no promises."
Target: Considered
Effects:
- employee_morale: +1
- set_flag: interview_scheduled
- set_flag: daughterevent
- set_variable: daughter_name
- set_variable: dad_name
EffectDescription: "This will slightly improve morale and schedule an interview."
- PassageName: Interview
Content: >-
The next day, you schedule an interview with {{ daughter_name }}. She arrives on time, dressed professionally and eager to impress.
"Thank you for considering me for this position," she says with a warm smile. "I'm excited about the opportunity to contribute to your company."
You now have to decide how to proceed with the interview.
Conditions:
interview_scheduled: 1
Links:
- Option: "Offer her the job."
Target: JobOffered
Effects:
- employee_morale: +5
- company_budget: -100
- set_flag: daughter_hired
- set_flag: interview_scheduled_done
EffectDescription: "Hiring her will improve morale but will require a financial investment."
- Option: "Politely decline."
Target: Declined
Effects:
- employee_morale: -1
- set_flag: interview_scheduled_done
EffectDescription: "Declining might slightly decrease morale."
- PassageName: OfficeEncounter
Content: >-
While walking through the office, you see {{ daughter_name }} hard at work. She looks up and smiles as you pass by.
"Thank you again for this opportunity," she says. "I won't let you down."
Her dedication is evident, and it seems she's fitting in well with the team.
Conditions:
daughter_hired: 1
Links:
- Option: "You're doing great. Keep it up."
Target: Encouraged
Effects:
- employee_morale: +2
EffectDescription: "This will boost her morale."
- Option: "Let's discuss your progress."
Target: DiscussProgress
Effects:
- employee_morale: +3
- set_flag: progress_meeting
EffectDescription: "This will slightly improve morale and set up a progress meeting."
- PassageName: Encouraged
Content: >-
{{ daughter_name }} beams at your encouragement and gets back to work with renewed energy.
Conditions:
daughter_hired: 1
progress_meeting: 0
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: DiscussProgress
Content: >-
You sit down with {{ daughter_name }} to discuss her progress. She shares her achievements and goals for the future.
"I've learned so much already," she says. "I have some ideas I'd like to share with you."
Conditions:
progress_meeting: 1
daughter_hired: 1
Links:
- Option: "Listen to her ideas."
Target: IdeasShared
Effects:
- employee_morale: +5
- company_reputation: +2
EffectDescription: "Listening to her ideas will boost her morale and improve company reputation."
- Option: "Encourage her to keep learning."
Target: KeepLearning
Effects:
- employee_morale: +3
EffectDescription: "Encouraging her to keep learning will slightly improve morale."
- PassageName: IdeasShared
Content: >-
{{ daughter_name }} shares innovative ideas that could benefit the company. You feel impressed by her creativity and drive.
Conditions:
progress_meeting: 1
daughter_hired: 1
Links:
- Option: "Implement some of her ideas."
Target: IdeasImplemented
Effects:
- company_reputation: +5
- company_budget: -50
EffectDescription: "Implementing her ideas will improve company reputation but will cost some money."
- Option: "Thank her and conclude the meeting."
Target: MeetingConcluded
Effects:
- employee_morale: +2
EffectDescription: "Thanking her will slightly improve morale."
- PassageName: KeepLearning
Content: >-
You encourage {{ daughter_name }} to keep learning and growing in her role. She nods enthusiastically, ready to take on new challenges.
Conditions:
progress_meeting: 1
daughter_hired: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: IdeasImplemented
Content: >-
Implementing {{ daughter_name }}'s ideas proves beneficial. The company sees improvements in efficiency and innovation.
Conditions:
progress_meeting: 1
daughter_hired: 1
Links:
- Option: "Celebrate the success."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: MeetingConcluded
Content: >-
You thank {{ daughter_name }} for her ideas and conclude the meeting. She leaves with a sense of accomplishment.
Conditions:
progress_meeting: 1
daughter_hired: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: UnexpectedAudit
Content: >-
The government has announced an unexpected audit of your company. Inspectors will be arriving tomorrow to review your financial records and operations.
This sudden development requires immediate attention and preparation. How will you handle this situation?
Conditions:
audit_done: 0
Links:
- Option: "Cooperate fully and provide all requested documents."
Target: Cooperate
Effects:
- company_reputation: +5
- company_budget: -50
- set_flag: audit_done
EffectDescription: "Cooperating will improve your reputation but will incur some costs."
- Option: "Attempt to delay the audit."
Target: DelayAudit
Effects:
- company_reputation: -5
- company_budget: -20
- set_flag: audit_done
EffectDescription: "Delaying the audit will harm your reputation and cost some money."
- PassageName: MarketOpportunity
Content: >-
You receive an intriguing proposal from a potential business partner. They offer an opportunity to expand into a new market, which could significantly boost your profits.
However, this expansion involves considerable risk and investment. What will you do?
Conditions: {}
Links:
- Option: "Accept the proposal and expand into the new market."
Target: MarketExpanded
Effects:
- company_reputation: +10
- company_budget: -200
- set_flag: expansion_success_check
EffectDescription: "Accepting will improve reputation significantly but will require a large investment."
- Option: "Decline the proposal and focus on existing markets."
Target: MarketDeclined
Effects:
- company_reputation: -1
EffectDescription: "Declining will slightly harm your reputation."
- PassageName: MarketExpansionSuccess
Content: >-
The market expansion has been a success! Your company's products are well received in the new market, and profits are on the rise.
This success story boosts your company's reputation and financial standing.
Conditions:
expansion_success_check: 1
Links:
- Option: "Celebrate and continue growing."
Target: GrowthContinues
Effects:
- company_reputation: +10
- company_budget: +300
EffectDescription: "Celebrating the success will greatly improve reputation and boost your budget."
- PassageName: MarketExpansionFailure
Content: >-
Unfortunately, the market expansion did not go as planned. The new market proved to be more challenging than anticipated, and the investment has not paid off.
This setback impacts your company's reputation and financial standing.
Conditions:
expansion_success_check: 1
Links:
- Option: "Regroup and refocus on core markets."
Target: Refocus
Effects:
- company_reputation: -5
- company_budget: -100
EffectDescription: "Refocusing will hurt your reputation and reduce your budget."
- PassageName: NewEmployeeConflict
Content: >-
A conflict arises between two employees, causing tension in the office. As the manager, you need to address the situation to maintain a healthy work environment.
"I can't work with them anymore," one employee says. "They are making my job impossible!"
Conditions:
conflict_resolved: 0
Links:
- Option: "Mediating the conflict."
Target: MediateConflict
Effects:
- employee_morale: +5
- set_flag: conflict_resolved
EffectDescription: "Mediating will improve overall morale."
- Option: "Taking disciplinary action."
Target: DisciplinaryAction
Effects:
- employee_morale: -5
- set_flag: conflict_resolved
EffectDescription: "Disciplinary action will harm morale."
- PassageName: MediateConflict
Content: >-
You mediate the conflict between the two employees, helping them reach a mutual understanding. The atmosphere in the office improves as a result.
Conditions:
conflict_resolved: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: DisciplinaryAction
Content: >-
You take disciplinary action against the employee causing the conflict. While the issue is resolved, it causes some unrest among other employees.
Conditions:
conflict_resolved: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: EmployeeAppreciation
Content: >-
You decide to show appreciation to your employees for their hard work by organizing a small office party. The gesture boosts morale and creates a positive atmosphere.
Conditions:
appreciation_done: 0
Links:
- Option: "Celebrate with your team."
Target: Celebration
Effects:
- employee_morale: +10
- company_budget: -50
- set_flag: appreciation_done
EffectDescription: "Celebrating will boost morale and cost some money."
- PassageName: Celebration
Content: >-
The office party is a success! Employees feel appreciated and motivated to continue giving their best effort.
Conditions:
appreciation_done: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: UnexpectedResignation
Content: >-
One of your key employees unexpectedly resigns, leaving a crucial role vacant. You need to act quickly to find a replacement and ensure a smooth transition.
Conditions:
resignation_done: 0
Links:
- Option: "Promote an existing employee."
Target: PromoteEmployee
Effects:
- employee_morale: +5
- set_flag: resignation_done
EffectDescription: "Promoting internally will boost morale."
- Option: "Hire externally."
Target: HireExternally
Effects:
- company_budget: -100
- set_flag: resignation_done
EffectDescription: "Hiring externally will cost some money."
- PassageName: PromoteEmployee
Content: >-
You promote an existing employee to fill the vacant role. The transition goes smoothly, and the promoted employee is eager to prove themselves.
Conditions:
resignation_done: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: HireExternally
Content: >-
You hire a new employee from outside the company to fill the vacant role. It takes some time for them to adjust, but they bring valuable skills and experience to the team.
Conditions:
resignation_done: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: UnexpectedPromotion
Content: >-
An employee has gone above and beyond their duties, showing exceptional performance. You consider promoting them to a higher position.
Conditions:
promotion_done: 0
Links:
- Option: "Promote the employee."
Target: PromotionSuccess
Effects:
- employee_morale: +15
- company_reputation: +5
- set_flag: promotion_done
EffectDescription: "Promoting the employee will greatly boost morale and improve company reputation."
- Option: "Delay the promotion."
Target: PromotionDelayed
Effects:
- employee_morale: -5
- set_flag: promotion_done
EffectDescription: "Delaying the promotion will harm morale."
- PassageName: PromotionSuccess
Content: >-
The promoted employee is thrilled and expresses their gratitude. Their performance continues to excel, setting a positive example for the team.
Conditions:
promotion_done: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""
- PassageName: PromotionDelayed
Content: >-
The employee is visibly disappointed but continues to perform their duties. The morale in the office takes a slight hit.
Conditions:
promotion_done: 1
Links:
- Option: "Continue."
Target: Continue
Effects: []
EffectDescription: ""