Narrative Scenes added
This commit is contained in:
parent
fd647c2407
commit
30222c98ee
687
main.py
687
main.py
@ -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
443
narrative_scenes.yml
Normal 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, I’ll 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 don’t 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: "I’ll 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: ""
|
||||||
Loading…
Reference in New Issue
Block a user