diff --git a/backend/MyBiz.slnx b/backend/MyBiz.slnx new file mode 100644 index 0000000..901a90b --- /dev/null +++ b/backend/MyBiz.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/backend/src/MyBiz.Core/Building.cs b/backend/src/MyBiz.Core/Building.cs new file mode 100644 index 0000000..bcf2be1 --- /dev/null +++ b/backend/src/MyBiz.Core/Building.cs @@ -0,0 +1,74 @@ +namespace MyBiz.Core; + +/// +/// Тип здания +/// +public enum BuildingType +{ + // Добыча сырья + Farm, // Ферма + CottonField, // Хлопковое поле + Mine, // Шахта + + // Производство + FoodFactory, // Пищекомбинат + TextileFactory, // Текстильная фабрика + SteelMill, // Сталелитейный завод + PlasticPlant, // Завод пластика + ElectronicsFactory, // Завод электроники + AutoFactory, // Автозавод + + // Торговля + GroceryStore, // Продуктовый магазин + ClothingStore, // Магазин одежды + ElectronicsStore, // Магазин электроники + AutoDealer, // Автосалон + Mall, // Торговый центр + + // Исследования + Laboratory, // Лаборатория + + // Склад + Warehouse // Склад +} + +/// +/// Здание +/// +public class Building +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public BuildingType Type { get; set; } + public string Name { get; set; } = string.Empty; + public string CityId { get; set; } = string.Empty; + + /// + /// Уровень здания (влияет на эффективность) + /// + public int Level { get; set; } = 1; + + /// + /// Стоимость постройки + /// + public decimal BuildCost { get; set; } + + /// + /// Стоимость содержания в тик + /// + public decimal UpkeepCost { get; set; } + + /// + /// Вместимость склада + /// + public int StorageCapacity { get; set; } + + /// + /// Количество рабочих мест + /// + public int WorkerSlots { get; set; } + + /// + /// Заполненность рабочими + /// + public int Workers { get; set; } +} diff --git a/backend/src/MyBiz.Core/City.cs b/backend/src/MyBiz.Core/City.cs new file mode 100644 index 0000000..023ee69 --- /dev/null +++ b/backend/src/MyBiz.Core/City.cs @@ -0,0 +1,47 @@ +namespace MyBiz.Core; + +/// +/// Размер города +/// +public enum CitySize +{ + Small, // Малый + Medium, // Средний + Large // Крупный +} + +/// +/// Город +/// +public class City +{ + public string Id { get; set; } = Guid.NewGuid().ToString(); + public string Name { get; set; } = string.Empty; + public string Country { get; set; } = string.Empty; + public CitySize Size { get; set; } + + /// + /// Население + /// + public int Population { get; set; } + + /// + /// Доступные здания + /// + public List Buildings { get; set; } = new(); + + /// + /// Рынок города (спрос на продукты) + /// + public Dictionary MarketDemand { get; set; } = new(); + + /// + /// Предложение на рынке + /// + public Dictionary MarketSupply { get; set; } = new(); + + /// + /// Текущие цены + /// + public Dictionary Prices { get; set; } = new(); +} diff --git a/backend/src/MyBiz.Core/Company.cs b/backend/src/MyBiz.Core/Company.cs new file mode 100644 index 0000000..a1d228d --- /dev/null +++ b/backend/src/MyBiz.Core/Company.cs @@ -0,0 +1,50 @@ +namespace MyBiz.Core; + +/// +/// Компания игрока +/// +public class Company +{ + public Guid Id { get; set; } = Guid.NewGuid(); + public string Name { get; set; } = string.Empty; + + /// + /// Доступные деньги + /// + public decimal Cash { get; set; } + + /// + /// Активы компании + /// + public decimal Assets { get; set; } + + /// + /// Пассивы (долги) + /// + public decimal Liabilities { get; set; } + + /// + /// Прибыль за последний период + /// + public decimal LastPeriodProfit { get; set; } + + /// + /// Список зданий компании + /// + public List Buildings { get; set; } = new(); + + /// + /// Складские запасы + /// + public Dictionary Inventory { get; set; } = new(); + + /// + /// Открытые технологии + /// + public HashSet UnlockedTechnologies { get; set; } = new(); + + /// + /// Рассчитать чистую стоимость + /// + public decimal NetWorth => Assets - Liabilities + Cash; +} diff --git a/backend/src/MyBiz.Core/Product.cs b/backend/src/MyBiz.Core/Product.cs new file mode 100644 index 0000000..dbeff02 --- /dev/null +++ b/backend/src/MyBiz.Core/Product.cs @@ -0,0 +1,65 @@ +namespace MyBiz.Core; + +/// +/// Категория продукта +/// +public enum ProductCategory +{ + RawMaterial, // Сырьё + Component, // Компоненты + ConsumerGoods // Товары народного потребления +} + +/// +/// Тип продукта +/// +public enum ProductType +{ + // Сырьё + Cotton, // Хлопок + Steel, // Сталь + Plastic, // Пластик + FoodRaw, // Сырьё для еды + + // Компоненты + Fabric, // Ткань + MetalParts, // Металлические детали + PlasticParts, // Пластиковые детали + ElectronicsComponents, // Электронные компоненты + + // Товары + Food, // Еда + Clothing, // Одежда + Electronics, // Электроника + Automobile // Автомобили +} + +/// +/// Продукт +/// +public class Product +{ + public ProductType Type { get; set; } + public string Name { get; set; } = string.Empty; + public ProductCategory Category { get; set; } + + /// + /// Базовая цена продукта + /// + public decimal BasePrice { get; set; } + + /// + /// Текущая цена (с учётом спроса/предложения) + /// + public decimal CurrentPrice { get; set; } + + /// + /// Доступное количество на рынке + /// + public int AvailableQuantity { get; set; } + + /// + /// Спрос на продукт + /// + public int Demand { get; set; } +} diff --git a/backend/src/MyBiz.Core/ProductionChain.cs b/backend/src/MyBiz.Core/ProductionChain.cs new file mode 100644 index 0000000..8a80870 --- /dev/null +++ b/backend/src/MyBiz.Core/ProductionChain.cs @@ -0,0 +1,37 @@ +namespace MyBiz.Core; + +/// +/// Шаг производственной цепочки +/// +public class ProductionStep +{ + /// + /// Требуемый продукт + /// + public ProductType InputProduct { get; set; } + + /// + /// Количество требуемого продукта + /// + public int InputQuantity { get; set; } + + /// + /// Время производства (в тиках) + /// + public int ProductionTime { get; set; } +} + +/// +/// Производственная цепочка +/// +public class ProductionChain +{ + public ProductType OutputProduct { get; set; } + public BuildingType RequiredBuilding { get; set; } + public List Steps { get; set; } = new(); + + /// + /// Количество выходного продукта за цикл + /// + public int OutputQuantity { get; set; } +} diff --git a/backend/tests/MyBiz.Tests/ProductTests.cs b/backend/tests/MyBiz.Tests/ProductTests.cs new file mode 100644 index 0000000..5d9cdf2 --- /dev/null +++ b/backend/tests/MyBiz.Tests/ProductTests.cs @@ -0,0 +1,41 @@ +using MyBiz.Core; + +namespace MyBiz.Tests; + +public class ProductTests +{ + [Fact] + public void Product_Creation_ShouldInitializeProperties() + { + // Arrange & Act + var product = new Product + { + Type = ProductType.Food, + Name = "Bread", + Category = ProductCategory.ConsumerGoods, + BasePrice = 10m + }; + + // Assert + Assert.Equal(ProductType.Food, product.Type); + Assert.Equal("Bread", product.Name); + Assert.Equal(ProductCategory.ConsumerGoods, product.Category); + Assert.Equal(10m, product.BasePrice); + } + + [Fact] + public void Product_CurrentPrice_ShouldDefaultToBasePrice() + { + // Arrange + var product = new Product + { + BasePrice = 25m + }; + + // Act + product.CurrentPrice = product.BasePrice; + + // Assert + Assert.Equal(25m, product.CurrentPrice); + } +} diff --git a/frontend/icon.svg b/frontend/icon.svg new file mode 100644 index 0000000..cfe7862 --- /dev/null +++ b/frontend/icon.svg @@ -0,0 +1,4 @@ + + + $ + diff --git a/frontend/project.godot b/frontend/project.godot new file mode 100644 index 0000000..6dc8886 --- /dev/null +++ b/frontend/project.godot @@ -0,0 +1,55 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="MyBiz - Economic Simulator" +run/main_scene="res://scenes/main.tscn" +config/features=PackedStringArray("4.0", "Forward Plus") +config/icon="res://icon.svg" + +[display] + +window/size/viewport_width=1280 +window/size/viewport_height=720 +window/stretch/mode="canvas_items" + +[input] + +move_up={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null) +] +} +move_down={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null) +] +} +move_left={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null) +] +} +move_right={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null) +] +} + +[layer_names] + +2d_physics/layer_1="Default" +2d_physics/layer_2="Buildings" +2d_physics/layer_3="UI" + +[rendering] + +renderer/rendering_method="forward_plus" diff --git a/frontend/scenes/main.tscn b/frontend/scenes/main.tscn new file mode 100644 index 0000000..8b22de6 --- /dev/null +++ b/frontend/scenes/main.tscn @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/scripts/core/GameData.cs b/frontend/scripts/core/GameData.cs new file mode 100644 index 0000000..2916d33 --- /dev/null +++ b/frontend/scripts/core/GameData.cs @@ -0,0 +1,13 @@ +using Godot; + +[GlobalClass] +public partial class GameData : Resource +{ + [Export] public string CompanyName { get; set; } = "My Company"; + [Export] public int StartYear { get; set; } = 1980; + [Export] public decimal StartingCash { get; set; } = 100000m; + + // Настройки карты + [Export] public int CityCount { get; set; } = 10; + [Export] public bool EnableImports { get; set; } = true; +} diff --git a/frontend/scripts/core/GameManager.cs b/frontend/scripts/core/GameManager.cs new file mode 100644 index 0000000..ead7d6f --- /dev/null +++ b/frontend/scripts/core/GameManager.cs @@ -0,0 +1,59 @@ +using Godot; + +/// +/// Менеджер игры - управляет состоянием игры +/// +public partial class GameManager : Node +{ + public static GameManager Instance { get; private set; } = null!; + + [Signal] public delegate void MoneyChangedEventHandler(decimal newAmount); + [Signal] public delegate void DateChangedEventHandler(int year, int month, int day); + + public decimal Money { get; private set; } = 100000m; + public int GameYear { get; private set; } = 1980; + public int GameMonth { get; private set; } = 1; + public int GameDay { get; private set; } = 1; + + public override void _Ready() + { + if (Instance != null && Instance != this) + { + QueueFree(); + return; + } + + Instance = this; + } + + public void AddMoney(decimal amount) + { + Money += amount; + EmitSignal(SignalName.MoneyChanged, Money); + } + + public void SpendMoney(decimal amount) + { + if (Money >= amount) + { + Money -= amount; + EmitSignal(SignalName.MoneyChanged, Money); + } + } + + public void AdvanceTime(int ticks) + { + GameDay += ticks; + if (GameDay > 30) + { + GameDay = 1; + GameMonth++; + if (GameMonth > 12) + { + GameMonth = 1; + GameYear++; + } + } + EmitSignal(SignalName.DateChanged, GameYear, GameMonth, GameDay); + } +} diff --git a/frontend/scripts/core/Main.cs b/frontend/scripts/core/Main.cs new file mode 100644 index 0000000..b0742bb --- /dev/null +++ b/frontend/scripts/core/Main.cs @@ -0,0 +1,13 @@ +using Godot; + +public partial class Main : Node2D +{ + public override void _Ready() + { + GD.Print("MyBiz - Game Started!"); + } + + public override void _Process(double delta) + { + } +} diff --git a/frontend/scripts/ui/GameUI.cs b/frontend/scripts/ui/GameUI.cs new file mode 100644 index 0000000..280200c --- /dev/null +++ b/frontend/scripts/ui/GameUI.cs @@ -0,0 +1,35 @@ +using Godot; + +/// +/// Базовый класс для всех UI элементов +/// +public partial class GameUI : Control +{ + protected GameManager GameManager => GameManager.Instance; + + public override void _Ready() + { + ConnectSignals(); + } + + protected virtual void ConnectSignals() + { + if (GameManager != null) + { + GameManager.MoneyChanged += OnMoneyChanged; + GameManager.DateChanged += OnDateChanged; + } + } + + protected virtual void OnMoneyChanged(decimal newAmount) { } + protected virtual void OnDateChanged(int year, int month, int day) { } + + public override void _ExitTree() + { + if (GameManager != null) + { + GameManager.MoneyChanged -= OnMoneyChanged; + GameManager.DateChanged -= OnDateChanged; + } + } +}