using FForumF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MenuTOD
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
try
{
// Проверяем, существует ли форма
Form2 form2 = new Form2();
// Настройка формы перед открытием
form2.StartPosition = FormStartPosition.CenterScreen;
form2.ShowInTaskbar = false; // если нужно
// Открываем форму модально
form2.ShowDialog();
// После закрытия формы
form2.Dispose(); // Освобождаем ресурсы
}
catch (Exception ex)
{
// Выводим сообщение об ошибке
MessageBox.Show($"Ошибка при открытии формы: {ex.Message}\n\n" +
$"Тип ошибки: {ex.GetType().Name}\n" +
$"StackTrace: {ex.StackTrace}",
"Ошибка",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
// Проверяем, существует ли форма
Form3 form3 = new Form3();
// Настройка формы перед открытием
form3.StartPosition = FormStartPosition.CenterScreen;
form3.ShowInTaskbar = false; // если нужно
// Открываем форму модально
form3.ShowDialog();
// После закрытия формы
form3.Dispose(); // Освобождаем ресурсы
}
catch (Exception ex)
{
// Выводим сообщение об ошибке
MessageBox.Show($"Ошибка при открытии формы: {ex.Message}\n\n" +
$"Тип ошибки: {ex.GetType().Name}\n" +
$"StackTrace: {ex.StackTrace}",
"Ошибка",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void button3_Click(object sender, EventArgs e)
{
try
{
// Проверяем, существует ли форма
MainForm MainForm = new MainForm();
// Настройка формы перед открытием
MainForm.StartPosition = FormStartPosition.CenterScreen;
MainForm.ShowInTaskbar = false; // если нужно
// Открываем форму модально
MainForm.ShowDialog();
// После закрытия формы
MainForm.Dispose(); // Освобождаем ресурсы
}
catch (Exception ex)
{
// Выводим сообщение об ошибке
MessageBox.Show($"Ошибка при открытии формы: {ex.Message}\n\n" +
$"Тип ошибки: {ex.GetType().Name}\n" +
$"StackTrace: {ex.StackTrace}",
"Ошибка",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void button4_Click(object sender, EventArgs e)
{
try
{
// Проверяем, существует ли форма
Form5 form5 = new Form5();
// Настройка формы перед открытием
form5.StartPosition = FormStartPosition.CenterScreen;
form5.ShowInTaskbar = false; // если нужно
// Открываем форму модально
form5.ShowDialog();
// После закрытия формы
form5.Dispose(); // Освобождаем ресурсы
}
catch (Exception ex)
{
// Выводим сообщение об ошибке
MessageBox.Show($"Ошибка при открытии формы: {ex.Message}\n\n" +
$"Тип ошибки: {ex.GetType().Name}\n" +
$"StackTrace: {ex.StackTrace}",
"Ошибка",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
}
Form1.Designer.cs
namespace MenuTOD
{
partial class Form1
{
///
/// Обязательная переменная конструктора.
///
private System.ComponentModel.IContainer components = null;
///
/// Освободить все используемые ресурсы.
///
/// истинно, если управляемый ресурс должен быть удален; иначе ложно.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Код, автоматически созданный конструктором форм Windows
///
/// Требуемый метод для поддержки конструктора — не изменяйте
/// содержимое этого метода с помощью редактора кода.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.button5 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox1.BackgroundImage")));
this.pictureBox1.Location = new System.Drawing.Point(-8, -3);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(835, 456);
this.pictureBox1.TabIndex = 1;
this.pictureBox1.TabStop = false;
//
// button2
//
this.button2.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.button2.Location = new System.Drawing.Point(12, 12);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(66, 31);
this.button2.TabIndex = 2;
this.button2.Text = "N3D";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button1
//
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.button1.Location = new System.Drawing.Point(12, 49);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(124, 31);
this.button1.TabIndex = 3;
this.button1.Text = "NSSpace";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button3
//
this.button3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.button3.Location = new System.Drawing.Point(12, 86);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(115, 31);
this.button3.TabIndex = 4;
this.button3.Text = "FForumF";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button4
//
this.button4.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.button4.Location = new System.Drawing.Point(12, 123);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(132, 31);
this.button4.TabIndex = 5;
this.button4.Text = "SlizarioPC";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// button5
//
this.button5.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
this.button5.Location = new System.Drawing.Point(12, 160);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(132, 31);
this.button5.TabIndex = 6;
this.button5.Text = "SlizarioPC";
this.button5.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button5);
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button1);
this.Controls.Add(this.button2);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
}
}
Form2.cs
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
namespace MenuTOD
{
public partial class Form2 : Form
{
// Цвета
private Color bgColor = Color.FromArgb(30, 30, 40);
private Color[] originalCubeColors = new Color[]
{
Color.FromArgb(251, 236, 93), // Желтый
Color.FromArgb(123, 145, 123), // Серо-зеленый
Color.FromArgb(0, 165, 80) // Зеленый
};
private Color[] cubeColors;
private Color outlineColor = Color.FromArgb(32, 96, 61);
// Цвета сторон сцены
private Color[] originalSceneSideColors = new Color[]
{
Color.FromArgb(60, 60, 80, 100), // Задняя стена
Color.FromArgb(60, 80, 60, 100), // Правая стена
Color.FromArgb(60, 100, 80, 60), // Левая стена
Color.FromArgb(60, 100, 60, 80), // Пол
Color.FromArgb(60, 60, 100, 80), // Потолок
Color.FromArgb(60, 100, 100, 60) // Передняя
};
private Color[] sceneSideColors;
// Цвета сеток
private Color[] originalGridColors = new Color[]
{
Color.FromArgb(80, 100, 150, 200), // XY плоскость
Color.FromArgb(80, 150, 100, 200), // XZ плоскость
Color.FromArgb(80, 200, 150, 100) // YZ плоскость
};
private Color[] gridColors;
// Кубы
private float cubeSize = 60;
private List cubes = new List
{
new Vector3(0, 0, 0),
new Vector3(150, 0, 150),
new Vector3(-150, 0, 300)
};
// Камера
private float camX = 35, camY = -35, camZ = 0, zoom = 1.2f;
private Point lastMouse;
private bool isRotating = false;
private bool isPanning = false;
private bool isOrbiting = false;
private Vector3 cameraPosition = new Vector3(0, 0, 500);
private Vector3 orbitCenter = new Vector3(0, 0, 0);
private float orbitRadius = 500;
private float orbitAngle = 0;
// Управление
private Timer gameTimer;
private Dictionary pressedKeys = new Dictionary();
private float moveSpeed = 8f;
private float rotateSpeed = 0.5f;
private float orbitSpeed = 2f;
// Режимы WASD
private enum WasdMode
{
MoveCubes, // O - движение кубов
MoveCamera // I - движение камеры
}
private WasdMode currentWasdMode = WasdMode.MoveCubes;
// Режим колёсика
private enum WheelMode
{
Zoom, // Обычный зум
HeightControl // Управление высотой (Z координатой)
}
private WheelMode currentWheelMode = WheelMode.Zoom;
private Keys lastModifierKey = Keys.None;
// Сетка
private int gridSize = 600;
private int originalGridStep = 50;
private int gridStep;
private int sceneSize = 800;
// Режимы управления и рандомизация
private ControlMode currentControlMode = ControlMode.Default;
private Random random = new Random();
private bool isRandomized = false;
// История для отмены
private List cubeColorsHistory = new List();
private List sceneColorsHistory = new List();
private List gridColorsHistory = new List();
private List gridStepHistory = new List();
private List> cubesHistory = new List>();
private enum ControlMode
{
Default,
RobloxStyle,
HeightControl,
Combined,
OrbitMode
}
public Form2()
{
InitializeComponent();
SetupForm();
}
private void SetupForm()
{
// Инициализируем цвета
cubeColors = (Color[])originalCubeColors.Clone();
sceneSideColors = (Color[])originalSceneSideColors.Clone();
gridColors = (Color[])originalGridColors.Clone();
gridStep = originalGridStep;
this.DoubleBuffered = true;
this.BackColor = bgColor;
pictureBox1.BackColor = bgColor;
this.KeyPreview = true;
this.Text = "3D СЦЕНА - Колёсико: ZOOM (обычный) / ВЫСОТА (с Alt/Ctrl/Shift)";
gameTimer = new Timer();
gameTimer.Interval = 16;
gameTimer.Tick += GameTimer_Tick;
gameTimer.Start();
InitializeKeys();
}
private void InitializeKeys()
{
pressedKeys[Keys.Left] = false;
pressedKeys[Keys.Right] = false;
pressedKeys[Keys.Up] = false;
pressedKeys[Keys.Down] = false;
pressedKeys[Keys.D2] = false;
pressedKeys[Keys.D3] = false;
pressedKeys[Keys.W] = false;
pressedKeys[Keys.S] = false;
pressedKeys[Keys.A] = false;
pressedKeys[Keys.D] = false;
pressedKeys[Keys.Q] = false;
pressedKeys[Keys.E] = false;
pressedKeys[Keys.R] = false;
pressedKeys[Keys.T] = false;
pressedKeys[Keys.N] = false;
pressedKeys[Keys.M] = false;
pressedKeys[Keys.O] = false;
pressedKeys[Keys.I] = false;
pressedKeys[Keys.ControlKey] = false;
pressedKeys[Keys.ShiftKey] = false;
pressedKeys[Keys.Alt] = false;
}
private void GameTimer_Tick(object sender, EventArgs e)
{
bool needRedraw = false;
float speed = moveSpeed;
if (currentControlMode == ControlMode.OrbitMode)
{
orbitAngle += orbitSpeed * 0.1f;
if (orbitAngle > 360) orbitAngle -= 360;
cameraPosition.X = orbitCenter.X + orbitRadius * (float)Math.Sin(orbitAngle * Math.PI / 180);
cameraPosition.Z = orbitCenter.Z + orbitRadius * (float)Math.Cos(orbitAngle * Math.PI / 180);
cameraPosition.Y = orbitCenter.Y + orbitRadius * 0.3f * (float)Math.Sin(orbitAngle * 0.5f * Math.PI / 180);
needRedraw = true;
}
// Обработка WASD в зависимости от режима
if (currentWasdMode == WasdMode.MoveCubes)
{
// Движение кубов
if (pressedKeys[Keys.W]) { foreach (var cube in cubes) cube.Z -= speed; needRedraw = true; }
if (pressedKeys[Keys.S]) { foreach (var cube in cubes) cube.Z += speed; needRedraw = true; }
if (pressedKeys[Keys.A]) { foreach (var cube in cubes) cube.X -= speed; needRedraw = true; }
if (pressedKeys[Keys.D]) { foreach (var cube in cubes) cube.X += speed; needRedraw = true; }
}
else if (currentWasdMode == WasdMode.MoveCamera)
{
// Движение камеры
if (pressedKeys[Keys.W]) { cameraPosition.Z -= speed * 2; needRedraw = true; }
if (pressedKeys[Keys.S]) { cameraPosition.Z += speed * 2; needRedraw = true; }
if (pressedKeys[Keys.A]) { cameraPosition.X -= speed * 2; needRedraw = true; }
if (pressedKeys[Keys.D]) { cameraPosition.X += speed * 2; needRedraw = true; }
}
// Управление в зависимости от режима
switch (currentControlMode)
{
case ControlMode.Default:
needRedraw |= HandleDefaultControls(speed);
break;
case ControlMode.RobloxStyle:
needRedraw |= HandleRobloxControls(speed);
break;
case ControlMode.HeightControl:
needRedraw |= HandleHeightControls(speed);
break;
case ControlMode.Combined:
needRedraw |= HandleDefaultControls(speed);
needRedraw |= HandleRobloxControls(speed);
needRedraw |= HandleHeightControls(speed);
break;
}
// Движение камеры вверх/вниз (Q/E)
if (pressedKeys[Keys.Q])
{
cameraPosition.Y += speed * 2;
needRedraw = true;
}
if (pressedKeys[Keys.E])
{
cameraPosition.Y -= speed * 2;
needRedraw = true;
}
if (needRedraw) pictureBox1.Invalidate();
}
private bool HandleDefaultControls(float speed)
{
bool changed = false;
if (pressedKeys[Keys.Left]) { foreach (var cube in cubes) cube.X -= speed; changed = true; }
if (pressedKeys[Keys.Right]) { foreach (var cube in cubes) cube.X += speed; changed = true; }
if (pressedKeys[Keys.Up]) { foreach (var cube in cubes) cube.Y -= speed; changed = true; }
if (pressedKeys[Keys.Down]) { foreach (var cube in cubes) cube.Y += speed; changed = true; }
return changed;
}
private bool HandleRobloxControls(float speed)
{
bool changed = false;
if (pressedKeys[Keys.W]) { foreach (var cube in cubes) cube.Z -= speed; changed = true; }
if (pressedKeys[Keys.S]) { foreach (var cube in cubes) cube.Z += speed; changed = true; }
if (pressedKeys[Keys.A]) { foreach (var cube in cubes) cube.X -= speed; changed = true; }
if (pressedKeys[Keys.D]) { foreach (var cube in cubes) cube.X += speed; changed = true; }
return changed;
}
private bool HandleHeightControls(float speed)
{
bool changed = false;
if (pressedKeys[Keys.D2]) { foreach (var cube in cubes) cube.Z += speed; changed = true; }
if (pressedKeys[Keys.D3]) { foreach (var cube in cubes) cube.Z -= speed; changed = true; }
return changed;
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.Clear(bgColor);
Matrix originalTransform = g.Transform;
g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2);
g.ScaleTransform(zoom, zoom);
// Применяем 3D вращение камеры
Matrix rotation = new Matrix();
rotation.Rotate(camZ, MatrixOrder.Append);
rotation.Rotate(camX, MatrixOrder.Append);
rotation.Rotate(camY, MatrixOrder.Append);
g.MultiplyTransform(rotation);
DrawSceneWalls(g);
DrawFull3DGrid(g);
List drawOrder = GetDrawOrder();
foreach (int idx in drawOrder)
DrawCube(g, cubes[idx], cubeColors[idx], (idx + 1).ToString());
DrawCoordinateAxes(g);
g.Transform = originalTransform;
DrawHUD(g);
DrawControls(g);
}
private void DrawSceneWalls(Graphics g)
{
DrawScenePlane(g, new Vector3(-sceneSize, -sceneSize, -sceneSize), new Vector3(sceneSize, -sceneSize, -sceneSize), new Vector3(sceneSize, -sceneSize, sceneSize), new Vector3(-sceneSize, -sceneSize, sceneSize), sceneSideColors[3]);
DrawScenePlane(g, new Vector3(-sceneSize, sceneSize, -sceneSize), new Vector3(sceneSize, sceneSize, -sceneSize), new Vector3(sceneSize, sceneSize, sceneSize), new Vector3(-sceneSize, sceneSize, sceneSize), sceneSideColors[4]);
DrawScenePlane(g, new Vector3(-sceneSize, -sceneSize, -sceneSize), new Vector3(sceneSize, -sceneSize, -sceneSize), new Vector3(sceneSize, sceneSize, -sceneSize), new Vector3(-sceneSize, sceneSize, -sceneSize), sceneSideColors[0]);
DrawScenePlane(g, new Vector3(-sceneSize, -sceneSize, sceneSize), new Vector3(sceneSize, -sceneSize, sceneSize), new Vector3(sceneSize, sceneSize, sceneSize), new Vector3(-sceneSize, sceneSize, sceneSize), sceneSideColors[5]);
DrawScenePlane(g, new Vector3(-sceneSize, -sceneSize, -sceneSize), new Vector3(-sceneSize, -sceneSize, sceneSize), new Vector3(-sceneSize, sceneSize, sceneSize), new Vector3(-sceneSize, sceneSize, -sceneSize), sceneSideColors[2]);
DrawScenePlane(g, new Vector3(sceneSize, -sceneSize, -sceneSize), new Vector3(sceneSize, -sceneSize, sceneSize), new Vector3(sceneSize, sceneSize, sceneSize), new Vector3(sceneSize, sceneSize, -sceneSize), sceneSideColors[1]);
}
private void DrawScenePlane(Graphics g, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, Color color)
{
PointF[] points = new PointF[4];
points[0] = ProjectToScreen(p1);
points[1] = ProjectToScreen(p2);
points[2] = ProjectToScreen(p3);
points[3] = ProjectToScreen(p4);
if (IsValidPolygon(points))
{
using (Brush brush = new SolidBrush(color))
g.FillPolygon(brush, points);
}
}
private void DrawFull3DGrid(Graphics g)
{
using (Pen xyPen = new Pen(gridColors[0], 1))
{
for (int z = -gridSize; z <= gridSize; z += gridStep * 2)
{
for (int x = -gridSize; x <= gridSize; x += gridStep)
{
PointF start = ProjectToScreen(new Vector3(x, -gridSize, z));
PointF end = ProjectToScreen(new Vector3(x, gridSize, z));
if (IsValidLine(start, end)) g.DrawLine(xyPen, start, end);
}
for (int y = -gridSize; y <= gridSize; y += gridStep)
{
PointF start = ProjectToScreen(new Vector3(-gridSize, y, z));
PointF end = ProjectToScreen(new Vector3(gridSize, y, z));
if (IsValidLine(start, end)) g.DrawLine(xyPen, start, end);
}
}
}
using (Pen xzPen = new Pen(gridColors[1], 1))
{
for (int y = -gridSize; y <= gridSize; y += gridStep * 2)
{
for (int x = -gridSize; x <= gridSize; x += gridStep)
{
PointF start = ProjectToScreen(new Vector3(x, y, -gridSize));
PointF end = ProjectToScreen(new Vector3(x, y, gridSize));
if (IsValidLine(start, end)) g.DrawLine(xzPen, start, end);
}
for (int z = -gridSize; z <= gridSize; z += gridStep)
{
PointF start = ProjectToScreen(new Vector3(-gridSize, y, z));
PointF end = ProjectToScreen(new Vector3(gridSize, y, z));
if (IsValidLine(start, end)) g.DrawLine(xzPen, start, end);
}
}
}
using (Pen yzPen = new Pen(gridColors[2], 1))
{
for (int x = -gridSize; x <= gridSize; x += gridStep * 2)
{
for (int y = -gridSize; y <= gridSize; y += gridStep)
{
PointF start = ProjectToScreen(new Vector3(x, y, -gridSize));
PointF end = ProjectToScreen(new Vector3(x, y, gridSize));
if (IsValidLine(start, end)) g.DrawLine(yzPen, start, end);
}
for (int z = -gridSize; z <= gridSize; z += gridStep)
{
PointF start = ProjectToScreen(new Vector3(x, -gridSize, z));
PointF end = ProjectToScreen(new Vector3(x, gridSize, z));
if (IsValidLine(start, end)) g.DrawLine(yzPen, start, end);
}
}
}
}
private void DrawCoordinateAxes(Graphics g)
{
DrawAxis(g, Color.Red, new Vector3(0, 0, 0), new Vector3(gridSize + 100, 0, 0), "X");
DrawAxis(g, Color.Green, new Vector3(0, 0, 0), new Vector3(0, gridSize + 100, 0), "Y");
DrawAxis(g, Color.Blue, new Vector3(0, 0, 0), new Vector3(0, 0, gridSize + 100), "Z");
}
private void DrawAxis(Graphics g, Color color, Vector3 start, Vector3 end, string label)
{
using (Pen pen = new Pen(color, 2))
{
PointF p1 = ProjectToScreen(start);
PointF p2 = ProjectToScreen(end);
if (IsValidLine(p1, p2))
{
g.DrawLine(pen, p1, p2);
DrawArrow(g, pen, p1, p2);
DrawAxisLabel(g, color, p2, label);
}
}
}
private void DrawArrow(Graphics g, Pen pen, PointF start, PointF end)
{
float arrowSize = 8;
float dx = end.X - start.X;
float dy = end.Y - start.Y;
float length = (float)Math.Sqrt(dx * dx + dy * dy);
if (length > 0)
{
dx /= length; dy /= length;
float perpX = -dy; float perpY = dx;
PointF arrow1 = new PointF(end.X - dx * arrowSize + perpX * arrowSize * 0.5f, end.Y - dy * arrowSize + perpY * arrowSize * 0.5f);
PointF arrow2 = new PointF(end.X - dx * arrowSize - perpX * arrowSize * 0.5f, end.Y - dy * arrowSize - perpY * arrowSize * 0.5f);
g.DrawLine(pen, end, arrow1);
g.DrawLine(pen, end, arrow2);
}
}
private void DrawAxisLabel(Graphics g, Color color, PointF position, string label)
{
try
{
using (Font font = new Font("Arial", 10, FontStyle.Bold))
using (Brush brush = new SolidBrush(color))
{
SizeF size = g.MeasureString(label, font);
g.DrawString(label, font, brush, position.X + 5, position.Y - size.Height / 2);
}
}
catch { }
}
private PointF ProjectToScreen(Vector3 point)
{
try
{
float x = point.X - cameraPosition.X;
float y = point.Y - cameraPosition.Y;
float z = point.Z - cameraPosition.Z;
float scale = 800 / (800 + z);
return new PointF(x * scale, y * scale);
}
catch { return PointF.Empty; }
}
private bool IsValidPoint(PointF point) => !float.IsNaN(point.X) && !float.IsNaN(point.Y) && !float.IsInfinity(point.X) && !float.IsInfinity(point.Y);
private bool IsValidLine(PointF p1, PointF p2) => IsValidPoint(p1) && IsValidPoint(p2);
private List GetDrawOrder()
{
List order = new List { 0, 1, 2 };
order.Sort((a, b) => DistanceToCamera(cubes[a]).CompareTo(DistanceToCamera(cubes[b])));
return order;
}
private float DistanceToCamera(Vector3 point)
{
float dx = point.X - cameraPosition.X;
float dy = point.Y - cameraPosition.Y;
float dz = point.Z - cameraPosition.Z;
return dx * dx + dy * dy + dz * dz;
}
private void DrawCube(Graphics g, Vector3 position, Color color, string label)
{
float hs = cubeSize / 2;
Vector3[] vertices = new Vector3[8];
vertices[0] = new Vector3(position.X - hs, position.Y - hs, position.Z - hs);
vertices[1] = new Vector3(position.X + hs, position.Y - hs, position.Z - hs);
vertices[2] = new Vector3(position.X + hs, position.Y + hs, position.Z - hs);
vertices[3] = new Vector3(position.X - hs, position.Y + hs, position.Z - hs);
vertices[4] = new Vector3(position.X - hs, position.Y - hs, position.Z + hs);
vertices[5] = new Vector3(position.X + hs, position.Y - hs, position.Z + hs);
vertices[6] = new Vector3(position.X + hs, position.Y + hs, position.Z + hs);
vertices[7] = new Vector3(position.X - hs, position.Y + hs, position.Z + hs);
int[][] faces = new int[][]
{
new int[] {0,1,2,3}, new int[] {4,5,6,7}, new int[] {1,5,6,2},
new int[] {0,4,7,3}, new int[] {3,2,6,7}, new int[] {0,1,5,4}
};
Color[] faceColors = new Color[]
{
AdjustColor(color, -60), AdjustColor(color, -40), AdjustColor(color, -20),
AdjustColor(color, 20), AdjustColor(color, 40), AdjustColor(color, -80)
};
PointF[] projected = new PointF[8];
for (int i = 0; i < 8; i++) projected[i] = ProjectToScreen(vertices[i]);
List faceOrder = new List { 0, 1, 2, 3, 4, 5 };
faceOrder.Sort((a, b) => GetFaceDepth(vertices, faces[b]).CompareTo(GetFaceDepth(vertices, faces[a])));
foreach (int faceIndex in faceOrder)
{
PointF[] points = new PointF[4];
for (int j = 0; j < 4; j++) points[j] = projected[faces[faceIndex][j]];
if (IsValidPolygon(points))
{
using (Brush brush = new SolidBrush(faceColors[faceIndex]))
g.FillPolygon(brush, points);
using (Pen pen = new Pen(outlineColor, 1))
g.DrawPolygon(pen, points);
}
}
DrawCubeLabel(g, position, label);
}
private float GetFaceDepth(Vector3[] vertices, int[] faceIndices)
{
float totalZ = 0;
foreach (int idx in faceIndices) totalZ += vertices[idx].Z;
return totalZ / faceIndices.Length;
}
private void DrawCubeLabel(Graphics g, Vector3 position, string label)
{
try
{
PointF screenPos = ProjectToScreen(position);
using (Font font = new Font("Arial", 14, FontStyle.Bold))
{
SizeF size = g.MeasureString(label, font);
float x = screenPos.X - size.Width / 2;
float y = screenPos.Y - size.Height / 2;
if (x > -1000 && x < 2000 && y > -1000 && y < 2000)
{
g.DrawString(label, font, Brushes.Black, x + 1, y + 1);
g.DrawString(label, font, Brushes.White, x, y);
}
}
}
catch { }
}
private bool IsValidPolygon(PointF[] points)
{
foreach (var point in points) if (!IsValidPoint(point)) return false;
return true;
}
private string GetDirection(float angle)
{
float normalizedAngle = angle % 360;
if (normalizedAngle < 0) normalizedAngle += 360;
if (normalizedAngle >= 315 || normalizedAngle < 45)
return "СЕВЕР ↑";
else if (normalizedAngle >= 45 && normalizedAngle < 135)
return "ВОСТОК →";
else if (normalizedAngle >= 135 && normalizedAngle < 225)
return "ЮГ ↓";
else
return "ЗАПАД ←";
}
private string GetWasdModeName(WasdMode mode)
{
return mode == WasdMode.MoveCubes ? "КУБЫ" : "КАМЕРА";
}
private string GetWheelModeName(WheelMode mode)
{
return mode == WheelMode.Zoom ? "ZOOM" : "ВЫСОТА (Z)";
}
private void DrawHUD(Graphics g)
{
try
{
int padding = 10;
int boxWidth = 340;
int boxHeight = 210;
using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 20, 20, 30)))
{
g.FillRectangle(bgBrush, padding, padding, boxWidth, boxHeight);
g.DrawRectangle(Pens.Gray, padding, padding, boxWidth, boxHeight);
}
using (Font font = new Font("Arial", 9, FontStyle.Bold))
{
// Режим WASD
string wasdText = $"WASD: {GetWasdModeName(currentWasdMode)} (O/I)";
g.DrawString(wasdText, font, currentWasdMode == WasdMode.MoveCubes ? Brushes.Cyan : Brushes.Magenta,
padding + 10, padding + 10);
// Режим колёсика
string wheelText = $"КОЛЁСИКО: {GetWheelModeName(currentWheelMode)}";
Brush wheelColor = currentWheelMode == WheelMode.Zoom ? Brushes.White : Brushes.Yellow;
g.DrawString(wheelText, font, wheelColor, padding + 10, padding + 30);
// Режим управления
string modeText = $"РЕЖИМ: {GetModeName(currentControlMode)}";
g.DrawString(modeText, font, GetModeColor(currentControlMode), padding + 10, padding + 50);
string randomStatus = isRandomized ? "РАНДОМИЗАЦИЯ: ✅ ВКЛ" : "РАНДОМИЗАЦИЯ: ❌ ВЫКЛ";
g.DrawString(randomStatus, font, isRandomized ? Brushes.Lime : Brushes.Gray, padding + 10, padding + 70);
float camAngle = camY % 360;
if (camAngle < 0) camAngle += 360;
g.DrawString($"НАПРАВЛЕНИЕ: {GetDirection(camAngle)}", font, Brushes.Yellow, padding + 10, padding + 90);
g.DrawString($"КАМЕРА: X:{cameraPosition.X:F0} Y:{cameraPosition.Y:F0} Z:{cameraPosition.Z:F0}",
font, Brushes.Cyan, padding + 10, padding + 110);
g.DrawString($"УГЛЫ: X={camX:F0}° Y={camY:F0}° Z={camZ:F0}°",
font, Brushes.White, padding + 10, padding + 130);
g.DrawString($"ZOOM: {zoom:F1}x | СЕТКА: {gridStep}",
font, Brushes.Yellow, padding + 10, padding + 150);
g.DrawString($"ОРБИТА: {(currentControlMode == ControlMode.OrbitMode ? "🌀 ВКЛ" : "⭕ ВЫКЛ")}",
font, currentControlMode == ControlMode.OrbitMode ? Brushes.Magenta : Brushes.Gray,
padding + 10, padding + 170);
// Информация о модификаторах
string modifiers = GetModifiersText();
g.DrawString($"МОДИФИКАТОРЫ: {modifiers}", font, Brushes.Orange, padding + 10, padding + 190);
}
}
catch { }
}
private string GetModifiersText()
{
List mods = new List();
if (pressedKeys[Keys.ControlKey]) mods.Add("Ctrl");
if (pressedKeys[Keys.ShiftKey]) mods.Add("Shift");
if (pressedKeys[Keys.Alt]) mods.Add("Alt");
return mods.Count > 0 ? string.Join("+", mods) : "нет";
}
private string GetModeName(ControlMode mode)
{
switch (mode)
{
case ControlMode.Default:
return "СТАНДАРТНЫЙ";
case ControlMode.RobloxStyle:
return "ROBLOX WASD";
case ControlMode.HeightControl:
return "ВЫСОТА 2/3";
case ControlMode.Combined:
return "ВСЁ ВМЕСТЕ";
case ControlMode.OrbitMode:
return "ВРАЩЕНИЕ";
default:
return "НЕИЗВЕСТНО";
}
}
private Brush GetModeColor(ControlMode mode)
{
switch (mode)
{
case ControlMode.Default:
return Brushes.White;
case ControlMode.RobloxStyle:
return Brushes.Cyan;
case ControlMode.HeightControl:
return Brushes.Lime;
case ControlMode.Combined:
return Brushes.Yellow;
case ControlMode.OrbitMode:
return Brushes.Magenta;
default:
return Brushes.White;
}
}
private string GetActiveKeysText()
{
List active = new List();
if (pressedKeys.ContainsKey(Keys.W) && pressedKeys[Keys.W]) active.Add("W");
if (pressedKeys.ContainsKey(Keys.A) && pressedKeys[Keys.A]) active.Add("A");
if (pressedKeys.ContainsKey(Keys.S) && pressedKeys[Keys.S]) active.Add("S");
if (pressedKeys.ContainsKey(Keys.D) && pressedKeys[Keys.D]) active.Add("D");
if (pressedKeys.ContainsKey(Keys.Q) && pressedKeys[Keys.Q]) active.Add("Q");
if (pressedKeys.ContainsKey(Keys.E) && pressedKeys[Keys.E]) active.Add("E");
if (pressedKeys.ContainsKey(Keys.R) && pressedKeys[Keys.R]) active.Add("R");
if (pressedKeys.ContainsKey(Keys.T) && pressedKeys[Keys.T]) active.Add("T");
if (pressedKeys.ContainsKey(Keys.N) && pressedKeys[Keys.N]) active.Add("N");
if (pressedKeys.ContainsKey(Keys.M) && pressedKeys[Keys.M]) active.Add("M");
if (pressedKeys.ContainsKey(Keys.O) && pressedKeys[Keys.O]) active.Add("O");
if (pressedKeys.ContainsKey(Keys.I) && pressedKeys[Keys.I]) active.Add("I");
if (pressedKeys.ContainsKey(Keys.D2) && pressedKeys[Keys.D2]) active.Add("2");
if (pressedKeys.ContainsKey(Keys.D3) && pressedKeys[Keys.D3]) active.Add("3");
return active.Count > 0 ? string.Join(" ", active) : "---";
}
private void DrawControls(Graphics g)
{
try
{
string[] controls = {
"=== КОЛЁСИКО МЫШИ (ГЛАВНОЕ!) ===",
"Обычное колёсико - ZOOM",
"Alt/Ctrl/Shift + колёсико - ВЫСОТА (Z)",
"",
"=== РЕЖИМЫ WASD ===",
"O - WASD двигает КУБЫ",
"I - WASD двигает КАМЕРУ",
"",
"=== 3D ВРАЩЕНИЕ КАМЕРЫ ===",
"Зажатое колесо + движение - вращение в 3D",
"",
"=== РЕЖИМЫ УПРАВЛЕНИЯ ===",
"R - ROBLOX WASD",
"E - ВЫСОТА 2/3",
"T - ВСЁ ВМЕСТЕ",
"",
"=== СПЕЦИАЛЬНЫЕ КОМАНДЫ ===",
"N - РАНДОМНЫЕ цвета и сетка",
"M - ОТМЕНА рандомизации",
"Ctrl+R - полный сброс",
"",
"=== ОСНОВНОЕ УПРАВЛЕНИЕ ===",
"ЛКМ - вращение камеры",
"ПКМ - панорамирование",
"Q/E - камера вверх/вниз",
"Стрелки - движение кубов",
"ESC - выход"
};
using (Font font = new Font("Arial", 8, FontStyle.Bold))
{
float maxWidth = 0;
foreach (string line in controls)
{
SizeF size = g.MeasureString(line, font);
if (size.Width > maxWidth) maxWidth = size.Width;
}
float boxWidth = maxWidth + 20;
float boxHeight = controls.Length * 16 + 10;
float boxX = pictureBox1.Width - boxWidth - 10;
float boxY = 10;
if (boxX < 0) boxX = 10;
using (Brush bgBrush = new SolidBrush(Color.FromArgb(220, 0, 0, 0)))
{
g.FillRectangle(bgBrush, boxX, boxY, boxWidth, boxHeight);
g.DrawRectangle(Pens.Gray, boxX, boxY, boxWidth, boxHeight);
}
for (int i = 0; i < controls.Length; i++)
{
Brush color = Brushes.White;
if (controls[i].Contains("КОЛЁСИКО")) color = Brushes.Yellow;
else if (controls[i].Contains("Alt/Ctrl/Shift")) color = Brushes.Lime;
else if (controls[i].Contains("WASD")) color = Brushes.Cyan;
else if (controls[i].Contains("3D")) color = Brushes.Magenta;
else if (controls[i].Contains("O -")) color = Brushes.Cyan;
else if (controls[i].Contains("I -")) color = Brushes.Magenta;
else if (controls[i].Contains("R -")) color = Brushes.Cyan;
else if (controls[i].Contains("E -")) color = Brushes.Lime;
else if (controls[i].Contains("T -")) color = Brushes.Yellow;
else if (controls[i].Contains("N -")) color = Brushes.Magenta;
else if (controls[i].Contains("M -")) color = Brushes.Orange;
else if (controls[i].Contains("Ctrl+R")) color = Brushes.Red;
else if (controls[i].Contains("===")) color = Brushes.Yellow;
float y = boxY + 5 + i * 16;
g.DrawString(controls[i], font, color, boxX + 10, y);
}
}
}
catch { }
}
private Color AdjustColor(Color c, int adj)
{
int Clamp(int val) => Math.Max(0, Math.Min(255, val));
return Color.FromArgb(Clamp(c.R + adj), Clamp(c.G + adj), Clamp(c.B + adj));
}
private void RandomizeEverything()
{
SaveCurrentState();
for (int i = 0; i < cubeColors.Length; i++)
cubeColors[i] = Color.FromArgb(random.Next(50, 255), random.Next(50, 255), random.Next(50, 255));
for (int i = 0; i < sceneSideColors.Length; i++)
sceneSideColors[i] = Color.FromArgb(60, random.Next(50, 200), random.Next(50, 200), random.Next(50, 200));
for (int i = 0; i < gridColors.Length; i++)
gridColors[i] = Color.FromArgb(80, random.Next(100, 255), random.Next(100, 255), random.Next(100, 255));
gridStep = random.Next(20, 101);
for (int i = 0; i < cubes.Count; i++)
{
cubes[i].X += random.Next(-100, 101);
cubes[i].Y += random.Next(-50, 51);
cubes[i].Z += random.Next(-100, 101);
}
isRandomized = true;
pictureBox1.Invalidate();
}
private void UndoRandomization()
{
if (cubeColorsHistory.Count > 0)
{
cubeColors = cubeColorsHistory[cubeColorsHistory.Count - 1];
sceneSideColors = sceneColorsHistory[sceneColorsHistory.Count - 1];
gridColors = gridColorsHistory[gridColorsHistory.Count - 1];
gridStep = gridStepHistory[gridStepHistory.Count - 1];
cubes = cubesHistory[cubesHistory.Count - 1];
cubeColorsHistory.RemoveAt(cubeColorsHistory.Count - 1);
sceneColorsHistory.RemoveAt(sceneColorsHistory.Count - 1);
gridColorsHistory.RemoveAt(gridColorsHistory.Count - 1);
gridStepHistory.RemoveAt(gridStepHistory.Count - 1);
cubesHistory.RemoveAt(cubesHistory.Count - 1);
isRandomized = cubeColorsHistory.Count > 0;
pictureBox1.Invalidate();
}
else
{
cubeColors = (Color[])originalCubeColors.Clone();
sceneSideColors = (Color[])originalSceneSideColors.Clone();
gridColors = (Color[])originalGridColors.Clone();
gridStep = originalGridStep;
cubes = new List { new Vector3(0, 0, 0), new Vector3(150, 0, 150), new Vector3(-150, 0, 300) };
isRandomized = false;
pictureBox1.Invalidate();
}
}
private void SaveCurrentState()
{
cubeColorsHistory.Add((Color[])cubeColors.Clone());
sceneColorsHistory.Add((Color[])sceneSideColors.Clone());
gridColorsHistory.Add((Color[])gridColors.Clone());
gridStepHistory.Add(gridStep);
List cubeCopy = new List();
foreach (var cube in cubes)
cubeCopy.Add(new Vector3(cube.X, cube.Y, cube.Z));
cubesHistory.Add(cubeCopy);
if (cubeColorsHistory.Count > 5)
{
cubeColorsHistory.RemoveAt(0);
sceneColorsHistory.RemoveAt(0);
gridColorsHistory.RemoveAt(0);
gridStepHistory.RemoveAt(0);
cubesHistory.RemoveAt(0);
}
}
// ===== МЫШКА =====
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isRotating = true;
lastMouse = e.Location;
pictureBox1.Cursor = Cursors.Hand;
}
else if (e.Button == MouseButtons.Right)
{
isPanning = true;
lastMouse = e.Location;
pictureBox1.Cursor = Cursors.SizeAll;
}
else if (e.Button == MouseButtons.Middle)
{
isOrbiting = true;
pictureBox1.Cursor = Cursors.Cross;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isRotating && e.Button == MouseButtons.Left)
{
int dx = e.X - lastMouse.X;
int dy = e.Y - lastMouse.Y;
camY += dx * rotateSpeed;
camX += dy * rotateSpeed;
camX = Math.Max(-90, Math.Min(90, camX));
lastMouse = e.Location;
pictureBox1.Invalidate();
}
else if (isPanning && e.Button == MouseButtons.Right)
{
int dx = e.X - lastMouse.X;
int dy = e.Y - lastMouse.Y;
cameraPosition.X -= dx * 2;
cameraPosition.Y -= dy * 2;
lastMouse = e.Location;
pictureBox1.Invalidate();
}
else if (isOrbiting && e.Button == MouseButtons.Middle)
{
int dx = e.X - lastMouse.X;
int dy = e.Y - lastMouse.Y;
camY += dx * rotateSpeed * 0.5f;
camX += dy * rotateSpeed * 0.3f;
camZ += dx * rotateSpeed * 0.2f;
camX = Math.Max(-180, Math.Min(180, camX));
camZ = Math.Max(-45, Math.Min(45, camZ));
lastMouse = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isRotating = false;
pictureBox1.Cursor = Cursors.Default;
}
else if (e.Button == MouseButtons.Right)
{
isPanning = false;
pictureBox1.Cursor = Cursors.Default;
}
else if (e.Button == MouseButtons.Middle)
{
isOrbiting = false;
pictureBox1.Cursor = Cursors.Default;
}
}
private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
// Определяем режим колёсика по нажатым модификаторам
bool ctrlPressed = (Control.ModifierKeys & Keys.Control) == Keys.Control;
bool altPressed = (Control.ModifierKeys & Keys.Alt) == Keys.Alt;
bool shiftPressed = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
if (ctrlPressed || altPressed || shiftPressed)
{
// РЕЖИМ ВЫСОТЫ (Z координаты) с модификаторами
currentWheelMode = WheelMode.HeightControl;
float heightChange = e.Delta * 0.5f; // Меньшая чувствительность для высоты
if (currentWasdMode == WasdMode.MoveCubes)
{
// Изменяем Z координату кубов
foreach (var cube in cubes)
cube.Z += heightChange;
}
else
{
// Изменяем Z координату камеры
cameraPosition.Z += heightChange;
}
}
else
{
// РЕЖИМ ZOOM (обычный)
currentWheelMode = WheelMode.Zoom;
zoom += e.Delta * 0.001f;
zoom = Math.Max(0.1f, Math.Min(5.0f, zoom));
}
pictureBox1.Invalidate();
}
// ===== КЛАВИАТУРА =====
private void Form2_KeyDown(object sender, KeyEventArgs e)
{
// Обновляем состояние модификаторов
if (e.KeyCode == Keys.ControlKey) pressedKeys[Keys.ControlKey] = true;
if (e.KeyCode == Keys.ShiftKey) pressedKeys[Keys.ShiftKey] = true;
if (e.KeyCode == Keys.Alt) pressedKeys[Keys.Alt] = true;
if (!pressedKeys.ContainsKey(e.KeyCode))
pressedKeys[e.KeyCode] = true;
else
pressedKeys[e.KeyCode] = true;
// Переключение режимов WASD
if (e.KeyCode == Keys.O && !e.Control && !e.Alt && !e.Shift)
{
currentWasdMode = WasdMode.MoveCubes;
}
else if (e.KeyCode == Keys.I && !e.Control && !e.Alt && !e.Shift)
{
currentWasdMode = WasdMode.MoveCamera;
}
// Переключение режимов управления
else if (e.KeyCode == Keys.R && !e.Control && !e.Alt && !e.Shift)
{
currentControlMode = currentControlMode != ControlMode.RobloxStyle ? ControlMode.RobloxStyle : ControlMode.Default;
}
else if (e.KeyCode == Keys.E && !e.Control && !e.Alt && !e.Shift)
{
currentControlMode = currentControlMode != ControlMode.HeightControl ? ControlMode.HeightControl : ControlMode.Default;
}
else if (e.KeyCode == Keys.T && !e.Control && !e.Alt && !e.Shift)
{
currentControlMode = currentControlMode != ControlMode.Combined ? ControlMode.Combined : ControlMode.Default;
}
else if (e.KeyCode == Keys.R && e.Control)
{
ResetView();
}
else if (e.KeyCode == Keys.N && !e.Control && !e.Alt && !e.Shift)
{
RandomizeEverything();
}
else if (e.KeyCode == Keys.M && !e.Control && !e.Alt && !e.Shift)
{
UndoRandomization();
}
else if (e.KeyCode == Keys.Escape)
{
this.Close();
}
pictureBox1.Invalidate();
}
private void Form2_KeyUp(object sender, KeyEventArgs e)
{
// Обновляем состояние модификаторов
if (e.KeyCode == Keys.ControlKey) pressedKeys[Keys.ControlKey] = false;
if (e.KeyCode == Keys.ShiftKey) pressedKeys[Keys.ShiftKey] = false;
if (e.KeyCode == Keys.Alt) pressedKeys[Keys.Alt] = false;
if (pressedKeys.ContainsKey(e.KeyCode))
pressedKeys[e.KeyCode] = false;
}
private void ResetView()
{
cubes = new List { new Vector3(0, 0, 0), new Vector3(150, 0, 150), new Vector3(-150, 0, 300) };
camX = 35; camY = -35; camZ = 0; zoom = 1.2f;
cameraPosition = new Vector3(0, 0, 500);
currentControlMode = ControlMode.Default;
currentWasdMode = WasdMode.MoveCubes;
currentWheelMode = WheelMode.Zoom;
orbitSpeed = 2f;
UndoRandomization();
}
private void Form2_Load(object sender, EventArgs e)
{
pictureBox1.MouseDown += pictureBox1_MouseDown;
pictureBox1.MouseMove += pictureBox1_MouseMove;
pictureBox1.MouseUp += pictureBox1_MouseUp;
pictureBox1.MouseWheel += pictureBox1_MouseWheel;
pictureBox1.Paint += PictureBox1_Paint;
this.KeyDown += Form2_KeyDown;
this.KeyUp += Form2_KeyUp;
this.Focus();
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
gameTimer?.Stop();
gameTimer?.Dispose();
}
private class Vector3
{
public float X, Y, Z;
public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;
namespace MenuTOD
{
public partial class Form3 : Form
{
private World world;
private PlayerShip player;
private bool[] keysPressed = new bool[256];
private PointF cameraPos = PointF.Empty;
private float scale = 1.0f;
private Random rnd = new Random();
private int worldSeed = 12345;
private SolarSystem currentSystem = null;
private bool editorMode = false;
private SolarSystem editingSystem = null;
private int selectedObjectType = 0;
private Color spaceColor = Color.FromArgb(10, 10, 40);
private bool cameraFollowsPlayer = true;
private float cooldownTimer = 0f;
private float timeScale = 1.0f;
private List starParticles = new List();
private List superShips = new List();
// Шаблоны для редактора
private List planetTemplates = new List();
private List starTemplates = new List();
public Form3()
{
InitializeComponent();
this.DoubleBuffered = true;
this.KeyPreview = true;
this.WindowState = FormWindowState.Maximized;
this.Text = "Космический Симулятор - Редактор Spore-стиль";
this.BackColor = Color.Black;
InitializeTemplates();
InitializeGame();
SetupEditorMenu();
Timer gameTimer = new Timer();
gameTimer.Interval = 16;
gameTimer.Tick += GameTimer_Tick;
gameTimer.Start();
GenerateWorld();
}
private void InitializeGame()
{
world = new World();
player = new PlayerShip();
GenerateWorld();
}
private void InitializeTemplates()
{
planetTemplates.Clear();
starTemplates.Clear();
// Создаем 18 типов планет по 10 вариантов каждый
string[] planetTypes = {
"Каменная", "Газовый гигант", "Ледяная", "Землеподобная", "Лава",
"Кислотная", "Мясная", "Голограмма", "Молочная", "Построенная",
"Стимпанк", "Водная", "Алмазная", "Урановая", "Город-планета",
"Живая", "Мега-планета", "Цитадель"
};
foreach (string type in planetTypes)
{
for (int i = 1; i <= 10; i++)
{
Color color = GetPlanetColor(type, i);
PlanetTemplate template = new PlanetTemplate
{
Name = type + "-" + i,
Type = type,
Color = color,
Radius = 8 + i + (type.Length % 5),
Composition = GetComposition(type),
CanBeColonized = CanBeColonized(type),
HasRings = i % 3 == 0,
HasAtmosphere = HasAtmosphere(type),
HasLife = type == "Землеподобная" && i > 5,
IsAcid = type == "Кислотная",
IsMeat = type == "Мясная",
IsHologram = type == "Голограмма",
IsMilk = type == "Молочная",
IsConstructed = type == "Построенная",
IsSteampunk = type == "Стимпанк",
IsWater = type == "Водная",
IsDiamond = type == "Алмазная",
IsUranium = type == "Урановая",
IsCity = type == "Город-планета",
IsAlive = type == "Живая",
IsMega = type == "Мега-планета",
IsCitadel = type == "Цитадель",
IsSystemCenter = type == "Мега-планета" && i % 3 == 0
};
// Устанавливаем дополнительные свойства в зависимости от типа
if (type == "Мясная")
template.BugCount = i * 2;
if (type == "Живая")
template.EyeCount = 4 + i % 8;
if (type == "Стимпанк")
template.GearCount = 3 + i % 5;
if (type == "Урановая")
template.RadiationLevel = 3 + i % 5;
if (type == "Алмазная")
template.SparkleIntensity = 5 + i;
if (type == "Город-планета")
{
template.BuildingCount = 50 + i * 10;
template.CityLights = true;
}
planetTemplates.Add(template);
}
}
// Создаем звезды
string[] starTypes = { "Желтый карлик", "Красный карлик", "Голубой гигант", "Красный гигант", "Двойная система", "Белый карлик", "Нейтронная звезда", "Черная дыра" };
foreach (string type in starTypes)
{
for (int i = 1; i <= 10; i++)
{
StarTemplate template = new StarTemplate
{
Name = type + "-" + i,
Type = type,
Color = GetStarColor(type),
Radius = GetStarRadius(type, i),
Temperature = GetStarTemperature(type),
IsBinary = type == "Двойная система",
IsNeutron = type == "Нейтронная звезда",
IsBlackHole = type == "Черная дыра"
};
starTemplates.Add(template);
}
}
}
private Color GetPlanetColor(string type, int variant)
{
switch (type)
{
case "Каменная":
return Color.FromArgb(80 + variant * 10, 80 + variant * 10, 80 + variant * 10);
case "Газовый гигант":
return Color.FromArgb(255, 165 + variant * 3, 0);
case "Ледяная":
return Color.FromArgb(150, 200 + variant * 2, 255);
case "Землеподобная":
return Color.FromArgb(0, 100 + variant * 5, 0);
case "Лава":
return Color.FromArgb(139 + variant * 5, 0, 0);
case "Кислотная":
return Color.FromArgb(0, 255 - variant * 5, 0);
case "Мясная":
return Color.FromArgb(139 + variant * 5, 69 + variant * 2, 19);
case "Голограмма":
return Color.FromArgb(100, 150 + variant * 5, 255, 150 + variant * 5);
case "Молочная":
return Color.FromArgb(255, 250 - variant * 5, 240 - variant * 5);
case "Построенная":
return Color.FromArgb(100 + variant * 5, 100 + variant * 5, 100 + variant * 5);
case "Стимпанк":
return Color.FromArgb(139 + variant * 2, 69 + variant, 19);
case "Водная":
return Color.FromArgb(0, 0, 139 + variant * 5);
case "Алмазная":
return Color.FromArgb(0, 255 - variant * 5, 255 - variant * 5);
case "Урановая":
return Color.FromArgb(0, 255 - variant * 5, 0);
case "Город-планета":
return Color.FromArgb(50 + variant * 5, 50 + variant * 5, 50 + variant * 5);
case "Живая":
return Color.FromArgb(255, 100 + variant * 5, 150 + variant * 5);
case "Мега-планета":
return Color.FromArgb(100 + variant * 5, 100 + variant * 5, 100);
case "Цитадель":
return Color.FromArgb(192 - variant * 2, 192 - variant * 2, 192 - variant * 2);
default:
return Color.Gray;
}
}
private Color GetStarColor(string type)
{
switch (type)
{
case "Желтый карлик":
return Color.Yellow;
case "Красный карлик":
return Color.OrangeRed;
case "Голубой гигант":
return Color.LightBlue;
case "Красный гигант":
return Color.Red;
case "Двойная система":
return Color.Orange;
case "Белый карлик":
return Color.White;
case "Нейтронная звезда":
return Color.Cyan;
case "Черная дыра":
return Color.FromArgb(30, 30, 30);
default:
return Color.White;
}
}
private float GetStarRadius(string type, int variant)
{
switch (type)
{
case "Желтый карлик":
return 30 + variant * 2;
case "Красный карлик":
return 20 + variant;
case "Голубой гигант":
return 50 + variant * 3;
case "Красный гигант":
return 60 + variant * 4;
case "Двойная система":
return 40 + variant * 2;
case "Белый карлик":
return 15 + variant;
case "Нейтронная звезда":
return 8 + variant;
case "Черная дыра":
return 25 + variant * 2;
default:
return 30 + variant;
}
}
private int GetStarTemperature(string type)
{
switch (type)
{
case "Желтый карлик":
return 5700;
case "Красный карлик":
return 3500;
case "Голубой гигант":
return 30000;
case "Красный гигант":
return 3500;
case "Двойная система":
return 6000;
case "Белый карлик":
return 10000;
case "Нейтронная звезда":
return 1000000;
case "Черная дыра":
return 0;
default:
return 5000;
}
}
private string GetComposition(string type)
{
switch (type)
{
case "Каменная":
return "Кремний, железо";
case "Газовый гигант":
return "Водород, гелий";
case "Ледяная":
return "Водяной лед";
case "Землеподобная":
return "Кислород, вода";
case "Лава":
return "Базальт, лава";
case "Кислотная":
return "Серная кислота";
case "Мясная":
return "Биомасса";
case "Голограмма":
return "Свет, данные";
case "Молочная":
return "Лактоза";
case "Построенная":
return "Металл";
case "Стимпанк":
return "Шестерни, пар";
case "Водная":
return "Вода, океаны";
case "Алмазная":
return "Углерод, алмазы";
case "Урановая":
return "Уран, радиация";
case "Город-планета":
return "Мегаполис";
case "Живая":
return "Сознание, плоть";
case "Мега-планета":
return "Колоссальная масса";
case "Цитадель":
return "Искусственная структура";
default:
return "Неизвестно";
}
}
private bool CanBeColonized(string type)
{
switch (type)
{
case "Каменная":
case "Газовый гигант":
case "Ледяная":
case "Лава":
case "Кислотная":
case "Урановая":
return false;
default:
return true;
}
}
private bool HasAtmosphere(string type)
{
switch (type)
{
case "Газовый гигант":
case "Землеподобная":
case "Кислотная":
case "Мясная":
case "Молочная":
case "Построенная":
case "Стимпанк":
case "Водная":
case "Город-планета":
case "Живая":
case "Мега-планета":
return true;
default:
return false;
}
}
private void SetupEditorMenu()
{
MenuStrip menu = new MenuStrip();
menu.BackColor = Color.FromArgb(40, 40, 40);
menu.ForeColor = Color.White;
ToolStripMenuItem fileMenu = new ToolStripMenuItem("Файл");
ToolStripMenuItem newWorld = new ToolStripMenuItem("Новый мир", null, (s, e) => NewWorld());
ToolStripMenuItem toggleEditor = new ToolStripMenuItem("Режим редактора", null, (s, e) => ToggleEditor());
ToolStripMenuItem createSystem = new ToolStripMenuItem("Создать систему", null, (s, e) => CreateSystem());
fileMenu.DropDownItems.AddRange(new ToolStripItem[] { newWorld, toggleEditor, createSystem });
menu.Items.Add(fileMenu);
this.MainMenuStrip = menu;
this.Controls.Add(menu);
}
private void NewWorld()
{
using (var dialog = new SeedInputDialog("Введите сид для мира:"))
{
if (dialog.ShowDialog() == DialogResult.OK)
{
worldSeed = dialog.Seed;
GenerateWorld();
}
}
}
private void ToggleEditor()
{
editorMode = !editorMode;
if (editorMode && currentSystem != null)
{
editingSystem = currentSystem;
}
else
{
editingSystem = null;
}
Invalidate();
}
private void CreateSystem()
{
using (var dialog = new SystemCreationDialog(starTemplates))
{
if (dialog.ShowDialog() == DialogResult.OK && dialog.CreatedSystem != null)
{
SolarSystem newSystem = dialog.CreatedSystem;
newSystem.Position = player.Position;
world.Systems.Add(newSystem);
currentSystem = newSystem;
editingSystem = newSystem;
scale = 0.02f;
editorMode = true;
Invalidate();
}
}
}
private void GenerateWorld()
{
world = new World();
starParticles.Clear();
superShips.Clear();
rnd = new Random(worldSeed);
currentSystem = null;
editingSystem = null;
editorMode = false;
cameraPos = PointF.Empty;
scale = 0.0005f; // Очень маленький масштаб для всей галактики
player.Position = new PointF(1000, 1000);
player.Velocity = PointF.Empty;
timeScale = 1.0f;
// Создаем фоновые звезды
for (int i = 0; i < 5000; i++)
{
starParticles.Add(new StarParticle(this.ClientSize, rnd));
}
// Создаем несколько супер-кораблей
for (int i = 0; i < 10; i++)
{
superShips.Add(new SuperShip(rnd));
}
// Генерация галактики (250-500 систем)
int systemCount = rnd.Next(250, 501);
world.SystemCount = systemCount;
GenerateGalaxy(systemCount);
Invalidate();
}
private void GenerateGalaxy(int systemCount)
{
// Спиральная галактика
float galaxyRadius = 40000;
int arms = 4;
for (int i = 0; i < systemCount; i++)
{
SolarSystem system = new SolarSystem();
float angle = (float)(rnd.NextDouble() * Math.PI * 2);
float distance = (float)Math.Sqrt(rnd.NextDouble()) * galaxyRadius;
// Исправленный расчет смещения рукава
double armAngle = angle * arms;
float armOffset = (float)(armAngle - Math.Floor(armAngle / (Math.PI * 2)) * (Math.PI * 2));
distance += (float)Math.Sin(armOffset) * 5000;
system.Position = new PointF(
(float)Math.Cos(angle) * distance,
(float)Math.Sin(angle) * distance
);
system.ID = world.Systems.Count + 1;
system.Name = "Система " + system.ID.ToString("0000");
GenerateSolarSystem(system, i);
world.Systems.Add(system);
}
}
private void GenerateSolarSystem(SolarSystem system, int index)
{
// Создаем звезду с улучшенной логикой
int starType = rnd.Next(100);
Star star = new Star();
star.Position = system.Position;
if (starType < 40)
{
star.Radius = rnd.Next(40, 70);
star.Color = GetStarColor("Желтый карлик");
star.Type = "Желтый карлик";
star.Temperature = 5700;
}
else if (starType < 65)
{
star.Radius = rnd.Next(30, 50);
star.Color = GetStarColor("Красный карлик");
star.Type = "Красный карлик";
star.Temperature = 3500;
}
else if (starType < 80)
{
star.Radius = rnd.Next(80, 120);
star.Color = GetStarColor("Голубой гигант");
star.Type = "Голубой гигант";
star.Temperature = 30000;
star.IsGiant = true;
}
else if (starType < 92)
{
star.Radius = rnd.Next(100, 160);
star.Color = GetStarColor("Красный гигант");
star.Type = "Красный гигант";
star.Temperature = 3500;
star.IsGiant = true;
}
else if (starType < 98)
{
star.Radius = rnd.Next(15, 25);
star.Color = GetStarColor("Белый карлик");
star.Type = "Белый карлик";
star.Temperature = 10000;
}
else if (starType < 99)
{
star.Radius = rnd.Next(8, 12);
star.Color = GetStarColor("Нейтронная звезда");
star.Type = "Нейтронная звезда";
star.Temperature = 1000000;
star.IsNeutron = true;
}
else
{
star.Radius = rnd.Next(25, 35);
star.Color = GetStarColor("Черная дыра");
star.Type = "Черная дыра";
star.Temperature = 0;
star.IsBlackHole = true;
}
// Двойная система (10% шанс)
if (rnd.Next(100) < 10)
{
star.IsBinary = true;
star.BinaryRadius = star.Radius * 0.6f;
star.BinaryColor = star.Type == "Красный гигант" ? GetStarColor("Белый карлик") :
star.Type == "Желтый карлик" ? GetStarColor("Красный карлик") :
GetStarColor("Желтый карлик");
}
system.Stars.Add(star);
// Создаем планеты с разнообразием типов
int planetCount = rnd.Next(2, 15);
for (int p = 0; p < planetCount; p++)
{
int planetIndex = rnd.Next(planetTemplates.Count);
PlanetTemplate planetTemplate = planetTemplates[planetIndex];
Planet planet = CreatePlanetFromTemplate(system, p, planetTemplate, rnd);
system.Planets.Add(planet);
}
}
private Planet CreatePlanetFromTemplate(SolarSystem system, int index, PlanetTemplate template, Random random)
{
Planet planet = new Planet();
float orbitRadius = 80 + index * 60 + random.Next(-15, 15);
float angle = (float)(random.NextDouble() * 2 * Math.PI);
planet.Position = new PointF(
system.Position.X + (float)Math.Cos(angle) * orbitRadius,
system.Position.Y + (float)Math.Sin(angle) * orbitRadius
);
planet.Name = template.Name;
planet.Radius = template.Radius;
planet.Color = template.Color;
planet.Type = template.Type;
planet.Composition = template.Composition;
planet.CanBeColonized = template.CanBeColonized;
planet.OrbitCenter = system.Position;
planet.OrbitRadius = orbitRadius;
planet.OrbitSpeed = (float)(0.01 + random.NextDouble() * 0.08) / (index + 1);
planet.SpinSpeed = (float)(random.NextDouble() * 0.03);
planet.SpinAngle = (float)(random.NextDouble() * 2 * Math.PI);
planet.HasRings = template.HasRings;
planet.HasAtmosphere = template.HasAtmosphere;
planet.IsMega = template.IsMega;
planet.IsCitadel = template.IsCitadel;
planet.IsAcid = template.IsAcid;
planet.IsMeat = template.IsMeat;
planet.IsHologram = template.IsHologram;
planet.IsMilk = template.IsMilk;
planet.IsConstructed = template.IsConstructed;
planet.IsSteampunk = template.IsSteampunk;
planet.IsWater = template.IsWater;
planet.IsDiamond = template.IsDiamond;
planet.IsUranium = template.IsUranium;
planet.IsCity = template.IsCity;
planet.IsAlive = template.IsAlive;
planet.HasLife = template.HasLife;
planet.HasBugs = template.HasBugs;
planet.BugCount = template.BugCount;
planet.EyeCount = template.EyeCount;
planet.CannotScan = template.CannotScan;
planet.GearCount = template.GearCount;
planet.RadiationLevel = template.RadiationLevel;
planet.SparkleIntensity = template.SparkleIntensity;
planet.BuildingCount = template.BuildingCount;
planet.CityLights = template.CityLights;
planet.IsSystemCenter = template.IsSystemCenter;
if (planet.HasRings)
{
planet.RingInner = planet.Radius + 4;
planet.RingOuter = planet.Radius + 20;
planet.RingColor = Color.Goldenrod;
}
return planet;
}
private void GameTimer_Tick(object sender, EventArgs e)
{
UpdatePlayerMovement();
player.Update(timeScale);
UpdateWorld();
UpdateCamera();
CheckSystemEntry();
Invalidate();
}
private void UpdatePlayerMovement()
{
float thrust = 0.15f * timeScale;
float rotationSpeed = 0.08f * timeScale;
if (keysPressed[(int)Keys.W] || keysPressed[(int)Keys.Up])
player.ThrustForward(thrust);
if (keysPressed[(int)Keys.S] || keysPressed[(int)Keys.Down])
player.ThrustForward(-thrust * 0.5f);
if (keysPressed[(int)Keys.A] || keysPressed[(int)Keys.Left])
player.Rotation -= rotationSpeed;
if (keysPressed[(int)Keys.D] || keysPressed[(int)Keys.Right])
player.Rotation += rotationSpeed;
if (keysPressed[(int)Keys.Space])
{
player.Velocity = new PointF(
player.Velocity.X * 0.9f,
player.Velocity.Y * 0.9f
);
}
// Управление временем Z/X
if (keysPressed[(int)Keys.Z] && timeScale > 0.1f)
timeScale *= 0.99f;
if (keysPressed[(int)Keys.X] && timeScale < 10.0f)
timeScale *= 1.01f;
if (cooldownTimer > 0) cooldownTimer -= 0.016f * timeScale;
}
private void UpdateWorld()
{
world.Update(timeScale);
foreach (var star in starParticles) star.Update();
foreach (var ship in superShips) ship.Update();
}
private void UpdateCamera()
{
if (cameraFollowsPlayer)
{
cameraPos = new PointF(
cameraPos.X + (player.Position.X - cameraPos.X) * 0.05f,
cameraPos.Y + (player.Position.Y - cameraPos.Y) * 0.05f
);
}
}
private void CheckSystemEntry()
{
if (currentSystem == null && cooldownTimer <= 0)
{
SolarSystem nearest = world.GetNearestSystem(player.Position);
if (nearest != null)
{
float dx = nearest.Position.X - player.Position.X;
float dy = nearest.Position.Y - player.Position.Y;
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
float entryDistance = 500 / scale;
if (distance < entryDistance)
{
EnterSystem(nearest);
}
}
}
}
private void EnterSystem(SolarSystem system)
{
if (cooldownTimer > 0) return;
currentSystem = system;
scale = 0.02f;
if (editorMode)
{
editingSystem = system;
}
MessageBox.Show($"Вход в систему: {system.Name}\nЗвезда: {system.Stars[0].Type}",
"Обнаружена система");
}
private void ExitSystem()
{
if (currentSystem != null)
{
currentSystem = null;
editingSystem = null;
scale = 0.0005f;
cooldownTimer = 1.0f;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(Color.Black);
// Рисуем фоновые звезды
foreach (var star in starParticles)
{
star.Draw(g, cameraPos, scale);
}
// Рисуем галактический фон
DrawGalaxyBackground(g);
g.TranslateTransform(ClientSize.Width / 2, ClientSize.Height / 2);
g.ScaleTransform(scale, scale);
g.TranslateTransform(-cameraPos.X, -cameraPos.Y);
// Рисуем игровой мир
world.Draw(g, player.Position, currentSystem, scale);
// Рисуем супер-корабли
foreach (var ship in superShips) ship.Draw(g, scale);
// Игрок
player.Draw(g);
g.ResetTransform();
// Рисуем интерфейс
DrawHUD(g);
if (editorMode && editingSystem != null)
{
DrawEditorUI(g);
}
}
private void DrawGalaxyBackground(Graphics g)
{
// Туманности и газовые облака
Random bgRnd = new Random(worldSeed);
for (int i = 0; i < 20; i++)
{
float x = bgRnd.Next(ClientSize.Width);
float y = bgRnd.Next(ClientSize.Height);
float size = bgRnd.Next(100, 400);
Color[] nebulaColors = {
Color.FromArgb(30, 100, 0, 200), // Фиолетовая
Color.FromArgb(30, 200, 100, 0), // Оранжевая
Color.FromArgb(30, 0, 150, 200), // Голубая
Color.FromArgb(30, 200, 0, 100) // Розовая
};
using (Brush nebulaBrush = new SolidBrush(nebulaColors[bgRnd.Next(nebulaColors.Length)]))
{
g.FillEllipse(nebulaBrush, x - size / 2, y - size / 2, size, size);
}
}
}
private void DrawHUD(Graphics g)
{
string info = $"Координаты: {player.Position.X:F0}, {player.Position.Y:F0}\n" +
$"Скорость: {Math.Sqrt(player.Velocity.X * player.Velocity.X + player.Velocity.Y * player.Velocity.Y):F1}\n" +
$"Масштаб: {scale:F6}x\n" +
$"Время: x{timeScale:F1}\n" +
$"Систем: {world.Systems.Count}";
using (Font hudFont = new Font("Arial", 10))
{
g.DrawString(info, hudFont, Brushes.White, 10, 10);
}
if (currentSystem != null)
{
using (Font modeFont = new Font("Arial", 12, FontStyle.Bold))
{
g.DrawString($"Система: {currentSystem.Name}", modeFont, Brushes.Yellow,
ClientSize.Width / 2 - 100, 10);
}
}
string controls = "WASD - движение\nПробел - торможение\nZ/X - время\nT - камера\nESC - выход из системы\nE - редактор";
if (editorMode)
{
controls += "\n\nРЕДАКТОР ВКЛЮЧЕН:\nЛКМ - выбрать объект\nПКМ - добавить планету\nDel - удалить объект";
}
using (Font controlFont = new Font("Arial", 9))
{
g.DrawString(controls, controlFont, Brushes.LightGray, 10, ClientSize.Height - 200);
}
}
private void DrawEditorUI(Graphics g)
{
using (Brush editorPanel = new SolidBrush(Color.FromArgb(200, 30, 30, 40)))
{
g.FillRectangle(editorPanel, ClientSize.Width - 350, 50, 340, 350);
}
string editorInfo = "РЕДАКТОР СИСТЕМЫ\n" + editingSystem.Name + "\n\n";
editorInfo += "Звезд: " + editingSystem.Stars.Count + "\n";
editorInfo += "Планет: " + editingSystem.Planets.Count + "\n\n";
editorInfo += "Выбрано: " + (selectedObjectType == 0 ? "Звезда" : "Планета") + "\n";
editorInfo += "ЛКМ - выбрать объект\nПКМ - добавить объект\nDel - удалить выбранный";
using (Font editorFont = new Font("Arial", 10))
{
g.DrawString(editorInfo, editorFont, Brushes.White, ClientSize.Width - 340, 60);
}
// Кнопки выбора типа
using (Brush buttonBrush = new SolidBrush(Color.FromArgb(100, 50, 100, 200)))
{
g.FillRectangle(buttonBrush, ClientSize.Width - 340, 200, 150, 30);
g.FillRectangle(buttonBrush, ClientSize.Width - 180, 200, 150, 30);
}
using (Font buttonFont = new Font("Arial", 10, FontStyle.Bold))
{
g.DrawString("Выбрать звезду", buttonFont, Brushes.White, ClientSize.Width - 335, 205);
g.DrawString("Выбрать планету", buttonFont, Brushes.White, ClientSize.Width - 175, 205);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue < 256) keysPressed[e.KeyValue] = true;
if (e.KeyCode == Keys.Add || e.KeyCode == Keys.Oemplus) scale *= 1.2f;
if (e.KeyCode == Keys.Subtract || e.KeyCode == Keys.OemMinus) scale *= 0.8f;
if (e.KeyCode == Keys.Escape && currentSystem != null) ExitSystem();
if (e.KeyCode == Keys.T) cameraFollowsPlayer = !cameraFollowsPlayer;
if (e.KeyCode == Keys.E) ToggleEditor();
if (scale < 0.0001f) scale = 0.0001f;
if (scale > 2f) scale = 2f;
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyValue < 256) keysPressed[e.KeyValue] = false;
base.OnKeyUp(e);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
float zoomFactor = 1.1f;
if (e.Delta > 0) scale *= zoomFactor;
else scale /= zoomFactor;
if (scale < 0.0001f) scale = 0.0001f;
if (scale > 2f) scale = 2f;
base.OnMouseWheel(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (editorMode && editingSystem != null)
{
HandleEditorLeftClick(e.Location);
}
else if (currentSystem != null)
{
PointF worldPos = ScreenToWorld(e.Location);
ShowPlanetInfo(worldPos);
}
}
else if (e.Button == MouseButtons.Right && editorMode && editingSystem != null)
{
ShowAddObjectDialog();
}
base.OnMouseDown(e);
}
private void HandleEditorLeftClick(Point location)
{
// Проверяем клик по кнопкам редактора
if (location.X > ClientSize.Width - 340 && location.X < ClientSize.Width - 190 &&
location.Y > 200 && location.Y < 230)
{
selectedObjectType = 0; // Выбрать звезду
return;
}
else if (location.X > ClientSize.Width - 180 && location.X < ClientSize.Width - 30 &&
location.Y > 200 && location.Y < 230)
{
selectedObjectType = 1; // Выбрать планету
return;
}
// Выбор объекта в системе
PointF worldPos = ScreenToWorld(location);
ShowObjectInfo(worldPos);
}
private PointF ScreenToWorld(Point screenPoint)
{
return new PointF(
(screenPoint.X - ClientSize.Width / 2) / scale + cameraPos.X,
(screenPoint.Y - ClientSize.Height / 2) / scale + cameraPos.Y
);
}
private void ShowObjectInfo(PointF worldPos)
{
if (editingSystem == null) return;
foreach (var star in editingSystem.Stars)
{
if (IsPointNearObject(worldPos, star.Position, star.Radius * 2))
{
ShowStarInfo(star);
return;
}
}
foreach (var planet in editingSystem.Planets)
{
if (IsPointNearObject(worldPos, planet.Position, planet.Radius * 2))
{
ShowPlanetInfo(planet);
return;
}
}
}
private bool IsPointNearObject(PointF point, PointF objectPos, float radius)
{
float dx = objectPos.X - point.X;
float dy = objectPos.Y - point.Y;
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
return distance < radius;
}
private void ShowStarInfo(Star star)
{
string info = "🌟 " + star.Type + "\n\n" +
"Радиус: " + star.Radius.ToString("F0") + "\n" +
"Температура: " + star.Temperature + "K\n" +
"Цвет: " + star.Color.Name;
MessageBox.Show(info, "Информация о звезде", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void ShowPlanetInfo(PointF worldPos)
{
if (currentSystem == null) return;
Planet closestPlanet = null;
float closestDistance = float.MaxValue;
foreach (var planet in currentSystem.Planets)
{
if (IsPointNearObject(worldPos, planet.Position, planet.Radius * 2))
{
float dx = planet.Position.X - worldPos.X;
float dy = planet.Position.Y - worldPos.Y;
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
if (distance < closestDistance)
{
closestDistance = distance;
closestPlanet = planet;
}
}
}
if (closestPlanet != null)
{
ShowPlanetInfo(closestPlanet);
}
}
private void ShowPlanetInfo(Planet planet)
{
if (planet.CannotScan)
{
MessageBox.Show("👁️ ЖИВАЯ ПЛАНЕТА\n\nСканирование невозможно!\nПланета активно сопротивляется.",
"Сканирование заблокировано", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string specialTraits = BuildSpecialTraits(planet);
string message = "🪐 " + planet.Name + "\n\n" +
"Тип: " + planet.Type + "\n" +
"Диаметр: " + (planet.Radius * 2).ToString("F0") + " ед.\n" +
"Состав: " + planet.Composition + "\n" +
"Орбита: " + planet.OrbitRadius.ToString("F0") + " ед.\n" +
"Колонизация: " + (planet.CanBeColonized ? "Возможна" : "Невозможна") + "\n\n" +
(string.IsNullOrEmpty(specialTraits) ? "🚫 Особых признаков" : "✨ ОСОБЫЕ ПРИЗНАКИ:\n" + specialTraits);
MessageBox.Show(message, "Сканирование планеты", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private string BuildSpecialTraits(Planet planet)
{
List traits = new List();
if (planet.IsAcid) traits.Add("🧪 КИСЛОТНЫЙ МИР");
if (planet.IsMeat) traits.Add("🥩 МЯСНАЯ ПЛАНЕТА");
if (planet.IsHologram) traits.Add("👁️ ГОЛОГРАФИЧЕСКАЯ");
if (planet.IsMilk) traits.Add("🥛 МОЛОЧНАЯ");
if (planet.IsConstructed) traits.Add("🏗️ ПОСТРОЕННАЯ");
if (planet.IsSteampunk) traits.Add("⚙️ СТИМПАНК (" + planet.GearCount + " шестерен)");
if (planet.IsWater) traits.Add("💧 ВОДНЫЙ МИР");
if (planet.IsDiamond) traits.Add("💎 АЛМАЗНАЯ");
if (planet.IsUranium) traits.Add("☢️ УРАНОВАЯ (ур. " + planet.RadiationLevel + ")");
if (planet.IsCity) traits.Add("🏙️ ГОРОД-ПЛАНЕТА");
if (planet.IsAlive) traits.Add("👁️ ЖИВАЯ (" + planet.EyeCount + " глаз)");
if (planet.HasLife) traits.Add("🌿 ОБИТАЕМАЯ");
if (planet.HasBugs) traits.Add("🐜 " + planet.BugCount + " жуков");
if (planet.HasRings) traits.Add("💍 ИМЕЕТ КОЛЬЦА");
if (planet.IsMega) traits.Add("🌟 МЕГА-ПЛАНЕТА");
if (planet.IsCitadel) traits.Add("🏰 ЦИТАДЕЛЬ");
if (planet.IsSystemCenter) traits.Add("☀️ ЗАМЕНЯЕТ ЗВЕЗДУ");
return string.Join("\n", traits);
}
private void ShowAddObjectDialog()
{
if (selectedObjectType == 0)
{
// Добавить звезду
using (var dialog = new ObjectSelectionDialog("Выберите звезду", starTemplates.ConvertAll(x => (object)x)))
{
if (dialog.ShowDialog() == DialogResult.OK && dialog.SelectedTemplate != null)
{
AddStarToSystem((StarTemplate)dialog.SelectedTemplate);
}
}
}
else
{
// Добавить планету
using (var dialog = new ObjectSelectionDialog("Выберите планету", planetTemplates.ConvertAll(x => (object)x)))
{
if (dialog.ShowDialog() == DialogResult.OK && dialog.SelectedTemplate != null)
{
AddPlanetToSystem((PlanetTemplate)dialog.SelectedTemplate);
}
}
}
}
private void AddStarToSystem(StarTemplate template)
{
Star newStar = new Star();
newStar.Position = editingSystem.Position;
newStar.Radius = template.Radius;
newStar.Color = template.Color;
newStar.Type = template.Type;
newStar.Temperature = template.Temperature;
newStar.IsBinary = template.IsBinary;
newStar.IsNeutron = template.IsNeutron;
newStar.IsBlackHole = template.IsBlackHole;
editingSystem.Stars.Add(newStar);
Invalidate();
}
private void AddPlanetToSystem(PlanetTemplate template)
{
Random random = new Random();
Planet newPlanet = CreatePlanetFromTemplate(editingSystem, editingSystem.Planets.Count, template, random);
editingSystem.Planets.Add(newPlanet);
Invalidate();
}
// Классы шаблонов
public class PlanetTemplate
{
public string Name { get; set; }
public string Type { get; set; }
public Color Color { get; set; }
public float Radius { get; set; }
public string Composition { get; set; }
public bool CanBeColonized { get; set; }
public bool HasRings { get; set; }
public bool HasAtmosphere { get; set; }
public bool HasLife { get; set; }
public bool HasBugs { get; set; }
public int BugCount { get; set; }
public int EyeCount { get; set; }
public bool CannotScan { get; set; }
public bool IsAcid { get; set; }
public bool IsMeat { get; set; }
public bool IsHologram { get; set; }
public bool IsMilk { get; set; }
public bool IsConstructed { get; set; }
public bool IsSteampunk { get; set; }
public bool IsWater { get; set; }
public bool IsDiamond { get; set; }
public bool IsUranium { get; set; }
public bool IsCity { get; set; }
public bool IsAlive { get; set; }
public bool IsMega { get; set; }
public bool IsCitadel { get; set; }
public bool IsSystemCenter { get; set; }
public int GearCount { get; set; }
public int RadiationLevel { get; set; }
public int SparkleIntensity { get; set; }
public int BuildingCount { get; set; }
public bool CityLights { get; set; }
}
public class StarTemplate
{
public string Name { get; set; }
public string Type { get; set; }
public Color Color { get; set; }
public float Radius { get; set; }
public int Temperature { get; set; }
public bool IsBinary { get; set; }
public bool IsNeutron { get; set; }
public bool IsBlackHole { get; set; }
}
// Диалоговые окна
private class SeedInputDialog : Form
{
public int Seed { get; private set; }
private TextBox seedBox;
public SeedInputDialog(string title)
{
Text = title;
Size = new Size(300, 150);
FormBorderStyle = FormBorderStyle.FixedDialog;
StartPosition = FormStartPosition.CenterParent;
Label label = new Label
{
Text = title,
Location = new Point(10, 10),
Size = new Size(280, 20)
};
seedBox = new TextBox
{
Location = new Point(10, 40),
Size = new Size(260, 20),
Text = new Random().Next().ToString()
};
Button okBtn = new Button
{
Text = "Создать",
Location = new Point(10, 80),
Size = new Size(120, 30),
DialogResult = DialogResult.OK
};
Button cancelBtn = new Button
{
Text = "Отмена",
Location = new Point(150, 80),
Size = new Size(120, 30),
DialogResult = DialogResult.Cancel
};
Controls.AddRange(new Control[] { label, seedBox, okBtn, cancelBtn });
AcceptButton = okBtn;
CancelButton = cancelBtn;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (DialogResult == DialogResult.OK && int.TryParse(seedBox.Text, out int seed))
{
Seed = seed;
}
base.OnFormClosing(e);
}
}
private class ObjectSelectionDialog : Form
{
public object SelectedTemplate { get; private set; }
private ListBox listBox;
private PictureBox previewBox;
private List
Form3.Designer.cs
namespace MenuTOD
{
partial class Form3
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form3";
}
#endregion
}
}
Form4.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using static FForumF.MainForm;
namespace FForumF
{
public partial class MainForm : Form
{
// Лого
private Label logoLabel;
private System.Windows.Forms.Timer logoTimer;
private int logoCounter = 0;
private Random rnd = new Random();
// Сервер
private TcpListener server;
private Thread serverThread;
private bool isRunning = false;
private int port = 8888;
private List clients = new List();
private string encryptionKey = "FFORUMF-SECURE-KEY-2024";
// Данные
private List topics = new List();
private ListBox topicsList;
private TextBox topicTitleBox;
private TextBox topicAuthorBox;
private RichTextBox topicContentBox;
private ListBox logListBox;
private Label ipLabel;
private bool showIP = true;
// Добавленные форматы файлов
private List supportedFormats = new List
{
".mp3", ".mp4", ".wav", ".avi", ".mov",
".png", ".jpg", ".jpeg", ".bmp", ".gif", ".svg", ".webp",
".txt", ".pdf", ".doc", ".docx", ".zip", ".rar"
};
public class ForumTopic
{
public string Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime Created { get; set; }
public List Messages { get; set; } = new List();
}
public class ForumMessage
{
public string Id { get; set; }
public string Author { get; set; }
public string Text { get; set; }
public DateTime Time { get; set; }
}
public MainForm()
{
InitializeForm();
StartLogoAnimation();
CreateSampleTopics();
}
private void InitializeForm()
{
this.Text = "FForumF - Secure P2P Forum";
this.Size = new Size(1200, 800);
this.StartPosition = FormStartPosition.CenterScreen;
this.BackColor = Color.FromArgb(10, 10, 10);
this.FormClosing += MainForm_FormClosing;
// Логотип
Panel logoPanel = new Panel();
logoPanel.Dock = DockStyle.Top;
logoPanel.Height = 70;
logoPanel.BackColor = Color.Black;
logoLabel = new Label();
logoLabel.Dock = DockStyle.Fill;
logoLabel.Font = new Font("Consolas", 24, FontStyle.Bold);
logoLabel.ForeColor = Color.Lime;
logoLabel.TextAlign = ContentAlignment.MiddleCenter;
logoLabel.Text = "FFORUMF ENCRYPTED";
logoPanel.Controls.Add(logoLabel);
// Основные вкладки
TabControl mainTabs = new TabControl();
mainTabs.Dock = DockStyle.Fill;
mainTabs.Font = new Font("Consolas", 9);
mainTabs.TabPages.Add(CreateHostTab());
mainTabs.TabPages.Add(CreateTopicsTab());
mainTabs.TabPages.Add(CreateCreateTab());
mainTabs.TabPages.Add(CreateLogsTab());
this.Controls.Add(mainTabs);
this.Controls.Add(logoPanel);
}
private TabPage CreateHostTab()
{
TabPage tab = new TabPage("Хостинг");
tab.BackColor = Color.FromArgb(20, 20, 20);
// Статус
Panel statusPanel = new Panel();
statusPanel.Size = new Size(1150, 150);
statusPanel.Location = new Point(20, 20);
statusPanel.BackColor = Color.FromArgb(30, 30, 30);
statusPanel.BorderStyle = BorderStyle.FixedSingle;
Label statusLabel = new Label();
statusLabel.Text = "СЕРВЕР ОФФЛАЙН";
statusLabel.Font = new Font("Consolas", 16, FontStyle.Bold);
statusLabel.ForeColor = Color.Red;
statusLabel.Location = new Point(20, 20);
ipLabel = new Label();
ipLabel.Text = "IP: Нажмите 'Показать IP'";
ipLabel.Font = new Font("Consolas", 12);
ipLabel.ForeColor = Color.Cyan;
ipLabel.Location = new Point(20, 60);
ipLabel.Size = new Size(800, 25);
Label clientsLabel = new Label();
clientsLabel.Text = "Клиентов: 0";
clientsLabel.Font = new Font("Consolas", 12);
clientsLabel.ForeColor = Color.Yellow;
clientsLabel.Location = new Point(20, 100);
// Кнопка показа/скрытия IP
Button toggleIPBtn = new Button();
toggleIPBtn.Text = "Показать IP";
toggleIPBtn.Font = new Font("Consolas", 10);
toggleIPBtn.Size = new Size(150, 30);
toggleIPBtn.Location = new Point(850, 55);
toggleIPBtn.BackColor = Color.FromArgb(60, 60, 120);
toggleIPBtn.ForeColor = Color.White;
toggleIPBtn.Click += (s, e) => ToggleIPVisibility(toggleIPBtn);
Button copyIPBtn = new Button();
copyIPBtn.Text = "Копировать IP";
copyIPBtn.Font = new Font("Consolas", 10);
copyIPBtn.Size = new Size(150, 30);
copyIPBtn.Location = new Point(850, 95);
copyIPBtn.BackColor = Color.FromArgb(0, 80, 120);
copyIPBtn.ForeColor = Color.White;
copyIPBtn.Click += CopyIPToClipboard;
statusPanel.Controls.Add(statusLabel);
statusPanel.Controls.Add(ipLabel);
statusPanel.Controls.Add(clientsLabel);
statusPanel.Controls.Add(toggleIPBtn);
statusPanel.Controls.Add(copyIPBtn);
// Кнопки управления
Button startBtn = new Button();
startBtn.Text = "ЗАПУСТИТЬ ХОСТ";
startBtn.Font = new Font("Consolas", 12, FontStyle.Bold);
startBtn.Size = new Size(300, 50);
startBtn.Location = new Point(20, 190);
startBtn.BackColor = Color.FromArgb(0, 100, 0);
startBtn.ForeColor = Color.White;
startBtn.Click += (s, e) => StartServer(statusLabel, ipLabel, clientsLabel, startBtn);
Button stopBtn = new Button();
stopBtn.Text = "ОСТАНОВИТЬ";
stopBtn.Font = new Font("Consolas", 12, FontStyle.Bold);
stopBtn.Size = new Size(300, 50);
stopBtn.Location = new Point(350, 190);
stopBtn.BackColor = Color.FromArgb(100, 0, 0);
stopBtn.ForeColor = Color.White;
stopBtn.Click += (s, e) => StopServer(statusLabel, ipLabel, clientsLabel, startBtn);
Button backupBtn = new Button();
backupBtn.Text = "СОХРАНИТЬ БЭКАП";
backupBtn.Font = new Font("Consolas", 12, FontStyle.Bold);
backupBtn.Size = new Size(300, 50);
backupBtn.Location = new Point(680, 190);
backupBtn.BackColor = Color.FromArgb(0, 60, 120);
backupBtn.ForeColor = Color.White;
backupBtn.Click += CreateBackup;
// Информация о порте
Panel portPanel = new Panel();
portPanel.Size = new Size(1150, 100);
portPanel.Location = new Point(20, 260);
portPanel.BackColor = Color.FromArgb(40, 40, 40);
portPanel.BorderStyle = BorderStyle.FixedSingle;
Label portLabel = new Label();
portLabel.Text = $"Порт: {port}";
portLabel.Font = new Font("Consolas", 14, FontStyle.Bold);
portLabel.ForeColor = Color.White;
portLabel.Location = new Point(20, 20);
Button changePortBtn = new Button();
changePortBtn.Text = "Изменить порт";
changePortBtn.Size = new Size(200, 30);
changePortBtn.Location = new Point(20, 60);
changePortBtn.Click += ChangePort;
portPanel.Controls.Add(portLabel);
portPanel.Controls.Add(changePortBtn);
// Инструкция
RichTextBox infoBox = new RichTextBox();
infoBox.Size = new Size(1150, 200);
infoBox.Location = new Point(20, 380);
infoBox.BackColor = Color.Black;
infoBox.ForeColor = Color.Lime;
infoBox.Font = new Font("Consolas", 9);
infoBox.Text = "ЗАЩИЩЕННЫЙ P2P ФОРУМ\n";
infoBox.Text += "=================================\n";
infoBox.Text += "• Сообщения шифруются только в файлах\n";
infoBox.Text += "• Поддержка многих форматов файлов\n";
infoBox.Text += "• Бэкап в .ffor формате\n";
infoBox.Text += "• Защита от взлома\n";
infoBox.Text += "• Приватность: скрытие IP\n";
infoBox.Text += "=================================\n";
infoBox.Text += "Форматы: MP3, MP4, PNG, JPG, GIF, SVG, WEBP,\n";
infoBox.Text += "TXT, PDF, DOC, ZIP, RAR и другие\n";
tab.Controls.Add(statusPanel);
tab.Controls.Add(startBtn);
tab.Controls.Add(stopBtn);
tab.Controls.Add(backupBtn);
tab.Controls.Add(portPanel);
tab.Controls.Add(infoBox);
return tab;
}
private TabPage CreateTopicsTab()
{
TabPage tab = new TabPage("Темы");
tab.BackColor = Color.FromArgb(20, 20, 20);
topicsList = new ListBox();
topicsList.Size = new Size(800, 500);
topicsList.Location = new Point(20, 20);
topicsList.BackColor = Color.Black;
topicsList.ForeColor = Color.Lime;
topicsList.Font = new Font("Consolas", 10);
topicsList.DisplayMember = "Title";
// Статистика
Label statsLabel = new Label();
statsLabel.Text = "Тем: 0 | Сообщений: 0";
statsLabel.ForeColor = Color.Cyan;
statsLabel.Location = new Point(20, 530);
statsLabel.Size = new Size(300, 25);
// Кнопки управления темами
Panel buttonPanel = new Panel();
buttonPanel.Size = new Size(300, 500);
buttonPanel.Location = new Point(840, 20);
buttonPanel.BackColor = Color.FromArgb(30, 30, 30);
Button viewBtn = CreateTopicButton("ПРОСМОТРЕТЬ", 20, ViewTopic);
Button replyBtn = CreateTopicButton("ОТВЕТИТЬ", 80, ReplyToTopic);
Button deleteBtn = CreateTopicButton("УДАЛИТЬ", 140, DeleteTopic);
Button exportBtn = CreateTopicButton("ЭКСПОРТ В .ffor", 200, ExportTopic);
Button refreshBtn = CreateTopicButton("ОБНОВИТЬ", 260, (s, e) => UpdateTopicsList(statsLabel));
buttonPanel.Controls.AddRange(new Control[] { viewBtn, replyBtn, deleteBtn, exportBtn, refreshBtn });
tab.Controls.Add(topicsList);
tab.Controls.Add(statsLabel);
tab.Controls.Add(buttonPanel);
this.Load += (s, e) => UpdateTopicsList(statsLabel);
return tab;
}
private TabPage CreateCreateTab()
{
TabPage tab = new TabPage("Новая тема");
tab.BackColor = Color.FromArgb(20, 20, 20);
// Поля ввода
Label titleLabel = new Label();
titleLabel.Text = "Заголовок:";
titleLabel.ForeColor = Color.White;
titleLabel.Location = new Point(20, 20);
topicTitleBox = new TextBox();
topicTitleBox.Size = new Size(600, 30);
topicTitleBox.Location = new Point(120, 17);
topicTitleBox.BackColor = Color.Black;
topicTitleBox.ForeColor = Color.Lime;
topicTitleBox.Font = new Font("Consolas", 11);
Label authorLabel = new Label();
authorLabel.Text = "Автор:";
authorLabel.ForeColor = Color.White;
authorLabel.Location = new Point(20, 70);
topicAuthorBox = new TextBox();
topicAuthorBox.Size = new Size(300, 30);
topicAuthorBox.Location = new Point(120, 67);
topicAuthorBox.BackColor = Color.Black;
topicAuthorBox.ForeColor = Color.Lime;
topicAuthorBox.Font = new Font("Consolas", 11);
Label contentLabel = new Label();
contentLabel.Text = "Сообщение:";
contentLabel.ForeColor = Color.White;
contentLabel.Location = new Point(20, 120);
topicContentBox = new RichTextBox();
topicContentBox.Size = new Size(800, 250);
topicContentBox.Location = new Point(20, 150);
topicContentBox.BackColor = Color.Black;
topicContentBox.ForeColor = Color.Lime;
topicContentBox.Font = new Font("Consolas", 10);
// Кнопка создания
Button createBtn = new Button();
createBtn.Text = "СОЗДАТЬ ТЕМУ";
createBtn.Size = new Size(300, 50);
createBtn.Location = new Point(20, 420);
createBtn.BackColor = Color.FromArgb(0, 80, 0);
createBtn.ForeColor = Color.White;
createBtn.Font = new Font("Consolas", 14, FontStyle.Bold);
createBtn.Click += CreateNewTopic;
tab.Controls.AddRange(new Control[] {
titleLabel, topicTitleBox,
authorLabel, topicAuthorBox,
contentLabel, topicContentBox,
createBtn
});
return tab;
}
private TabPage CreateLogsTab()
{
TabPage tab = new TabPage("Логи");
tab.BackColor = Color.Black;
logListBox = new ListBox();
logListBox.Dock = DockStyle.Fill;
logListBox.BackColor = Color.Black;
logListBox.ForeColor = Color.Lime;
logListBox.Font = new Font("Consolas", 9);
logListBox.Items.Add($"[{DateTime.Now:HH:mm:ss}] FFORUMF LOG");
logListBox.Items.Add($"[{DateTime.Now:HH:mm:ss}] Система запущена");
Panel logPanel = new Panel();
logPanel.Dock = DockStyle.Bottom;
logPanel.Height = 50;
logPanel.BackColor = Color.FromArgb(30, 30, 30);
Button clearLogsBtn = new Button();
clearLogsBtn.Text = "Очистить логи";
clearLogsBtn.Size = new Size(150, 30);
clearLogsBtn.Location = new Point(20, 10);
clearLogsBtn.Click += (s, e) => logListBox.Items.Clear();
Button saveLogsBtn = new Button();
saveLogsBtn.Text = "Сохранить логи";
saveLogsBtn.Size = new Size(150, 30);
saveLogsBtn.Location = new Point(180, 10);
saveLogsBtn.Click += SaveLogs;
logPanel.Controls.Add(clearLogsBtn);
logPanel.Controls.Add(saveLogsBtn);
tab.Controls.Add(logListBox);
tab.Controls.Add(logPanel);
return tab;
}
private Button CreateTopicButton(string text, int y, EventHandler handler)
{
Button btn = new Button();
btn.Text = text;
btn.Size = new Size(280, 40);
btn.Location = new Point(10, y);
btn.BackColor = Color.FromArgb(50, 50, 50);
btn.ForeColor = Color.White;
btn.Font = new Font("Consolas", 9);
btn.Click += handler;
return btn;
}
private void StartLogoAnimation()
{
logoTimer = new System.Windows.Forms.Timer();
logoTimer.Interval = 50;
logoTimer.Tick += (s, e) =>
{
logoCounter++;
string[] oriyaChars = {
"ଅ", "ଆ", "ଇ", "ଈ", "ଉ", "ଊ", "ଋ", "ୠ", "ଌ", "ୡ",
"ଏ", "ଐ", "ଓ", "ଔ", "କ", "ଖ", "ଗ", "ଘ", "ଙ", "ଚ",
"ଛ", "ଜ", "ଝ", "ଞ", "ଟ", "ଠ", "ଡ", "ଢ", "ଣ", "ତ",
"ଥ", "ଦ", "ଧ", "ନ", "ପ", "ଫ", "ବ", "ଭ", "ମ", "ଯ",
"ର", "ଲ", "ଳ", "ୱ", "ଶ", "ଷ", "ସ", "ହ", "ଡୱ", "ଢୱ"
};
StringBuilder logoText = new StringBuilder("FFORUMF ");
for (int i = 0; i < 12; i++)
{
logoText.Append(oriyaChars[rnd.Next(oriyaChars.Length)]);
}
if (logoCounter % 8 == 0)
{
Color[] colors = {
Color.Lime, Color.Cyan, Color.Magenta,
Color.Yellow, Color.Orange, Color.Pink,
Color.SpringGreen, Color.Aqua, Color.Fuchsia
};
logoLabel.ForeColor = colors[rnd.Next(colors.Length)];
}
logoLabel.Text = logoText.ToString();
};
logoTimer.Start();
}
// ===================== ШИФРОВАНИЕ (ТОЛЬКО ДЛЯ ФАЙЛОВ) =====================
private string EncryptForFile(string text)
{
if (string.IsNullOrEmpty(text)) return text;
try
{
// 1. Шифр Цезаря (сдвиг на 5)
string step1 = CaesarCipher(text, 5);
// 2. Отражаем строку
string step2 = ReverseString(step1);
// 3. Преобразуем в бинарный вид
string step3 = StringToBinary(step2);
// 4. Заменяем 1 на H, 0 на A
string step4 = step3.Replace('1', 'H').Replace('0', 'A');
return step4;
}
catch
{
return text;
}
}
private string DecryptFromFile(string encrypted)
{
if (string.IsNullOrEmpty(encrypted)) return encrypted;
try
{
// 4. Возвращаем 1 и 0
string step4 = encrypted.Replace('H', '1').Replace('A', '0');
// 3. Бинарный в текст
string step3 = BinaryToString(step4);
// 2. Возвращаем отражение
string step2 = ReverseString(step3);
// 1. Дешифруем Цезаря
string step1 = CaesarCipher(step2, -5);
return step1;
}
catch
{
return "DECRYPT_ERROR";
}
}
private string CaesarCipher(string text, int shift)
{
if (string.IsNullOrEmpty(text)) return text;
shift %= 26;
char[] buffer = text.ToCharArray();
for (int i = 0; i < buffer.Length; i++)
{
char letter = buffer[i];
if (char.IsLetter(letter))
{
char offset = char.IsUpper(letter) ? 'A' : 'a';
buffer[i] = (char)(((letter + shift - offset + 26) % 26) + offset);
}
}
return new string(buffer);
}
private string ReverseString(string s)
{
if (string.IsNullOrEmpty(s)) return s;
char[] arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
private string StringToBinary(string data)
{
if (string.IsNullOrEmpty(data)) return "";
StringBuilder binary = new StringBuilder();
foreach (char c in data)
{
binary.Append(Convert.ToString(c, 2).PadLeft(8, '0'));
}
return binary.ToString();
}
private string BinaryToString(string binary)
{
if (string.IsNullOrEmpty(binary) || binary.Length % 8 != 0)
return binary;
try
{
List bytes = new List();
for (int i = 0; i < binary.Length; i += 8)
{
if (i + 8 <= binary.Length)
{
string byteString = binary.Substring(i, 8);
bytes.Add(Convert.ToByte(byteString, 2));
}
}
return Encoding.UTF8.GetString(bytes.ToArray());
}
catch
{
return binary;
}
}
// ===================== УПРАВЛЕНИЕ IP =====================
private void ToggleIPVisibility(Button toggleBtn)
{
showIP = !showIP;
if (showIP)
{
toggleBtn.Text = "Скрыть IP";
if (isRunning)
{
string localIP = GetLocalIPAddress();
ipLabel.Text = $"IP: {localIP}:{port}";
}
else
{
ipLabel.Text = "IP: Сервер не запущен";
}
}
else
{
toggleBtn.Text = "Показать IP";
ipLabel.Text = "IP: ***********";
}
}
private void CopyIPToClipboard(object sender, EventArgs e)
{
if (isRunning && showIP)
{
string localIP = GetLocalIPAddress();
Clipboard.SetText($"{localIP}:{port}");
AddLog("IP скопирован в буфер обмена");
MessageBox.Show($"IP скопирован: {localIP}:{port}", "Успех",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Сначала запустите сервер и покажите IP", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void ChangePort(object sender, EventArgs e)
{
// Создаем свою форму для ввода порта
Form portForm = new Form();
portForm.Text = "Изменение порта";
portForm.Size = new Size(300, 150);
portForm.StartPosition = FormStartPosition.CenterScreen;
portForm.BackColor = Color.FromArgb(30, 30, 30);
Label label = new Label();
label.Text = "Введите новый порт (1024-65535):";
label.ForeColor = Color.White;
label.Location = new Point(20, 20);
label.Size = new Size(250, 20);
TextBox portBox = new TextBox();
portBox.Text = port.ToString();
portBox.Location = new Point(20, 50);
portBox.Size = new Size(240, 25);
portBox.BackColor = Color.Black;
portBox.ForeColor = Color.Lime;
Button okBtn = new Button();
okBtn.Text = "OK";
okBtn.Location = new Point(20, 85);
okBtn.Size = new Size(100, 30);
okBtn.BackColor = Color.FromArgb(0, 100, 0);
okBtn.ForeColor = Color.White;
okBtn.DialogResult = DialogResult.OK;
Button cancelBtn = new Button();
cancelBtn.Text = "Отмена";
cancelBtn.Location = new Point(130, 85);
cancelBtn.Size = new Size(100, 30);
cancelBtn.BackColor = Color.FromArgb(100, 0, 0);
cancelBtn.ForeColor = Color.White;
cancelBtn.DialogResult = DialogResult.Cancel;
portForm.Controls.Add(label);
portForm.Controls.Add(portBox);
portForm.Controls.Add(okBtn);
portForm.Controls.Add(cancelBtn);
portForm.AcceptButton = okBtn;
portForm.CancelButton = cancelBtn;
if (portForm.ShowDialog() == DialogResult.OK)
{
string newPort = portBox.Text;
if (int.TryParse(newPort, out int portNum) && portNum >= 1024 && portNum <= 65535)
{
if (!isRunning)
{
port = portNum;
AddLog($"Порт изменен на: {port}");
MessageBox.Show($"Порт изменен на: {port}", "Успех",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Остановите сервер перед изменением порта", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("Неверный номер порта!", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
// ===================== ОСНОВНЫЕ МЕТОДЫ =====================
private void CreateSampleTopics()
{
topics.Add(new ForumTopic
{
Id = Guid.NewGuid().ToString(),
Title = "Добро пожаловать в FForumF!",
Author = "Система",
Content = "Это защищенный P2P форум. Сообщения шифруются только в файлах .ffor!",
Created = DateTime.Now
});
AddLog("Созданы примерные темы");
}
private void UpdateTopicsList(Label statsLabel = null)
{
if (topicsList != null && !topicsList.IsDisposed)
{
topicsList.Items.Clear();
foreach (var topic in topics.OrderByDescending(t => t.Created))
{
topicsList.Items.Add(topic);
}
if (statsLabel != null && !statsLabel.IsDisposed)
{
int totalMessages = topics.Sum(t => t.Messages.Count);
statsLabel.Text = $"Тем: {topics.Count} | Сообщений: {totalMessages}";
}
}
}
private void ViewTopic(object sender, EventArgs e)
{
if (topicsList.SelectedItem is ForumTopic selectedTopic)
{
TopicViewForm viewForm = new TopicViewForm(selectedTopic, this);
viewForm.ShowDialog();
UpdateTopicsList();
}
}
private void ReplyToTopic(object sender, EventArgs e)
{
if (topicsList.SelectedItem is ForumTopic selectedTopic)
{
ReplyForm replyForm = new ReplyForm(selectedTopic, this);
if (replyForm.ShowDialog() == DialogResult.OK)
{
UpdateTopicsList();
AddLog($"Добавлен ответ в тему: {selectedTopic.Title}");
}
}
}
private void DeleteTopic(object sender, EventArgs e)
{
if (topicsList.SelectedItem is ForumTopic selectedTopic)
{
if (MessageBox.Show($"Удалить тему '{selectedTopic.Title}' со всеми сообщениями?",
"Подтверждение", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
topics.Remove(selectedTopic);
UpdateTopicsList();
AddLog($"Удалена тема: {selectedTopic.Title}");
}
}
}
private void ExportTopic(object sender, EventArgs e)
{
if (topicsList.SelectedItem is ForumTopic selectedTopic)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "FFOR файлы|*.ffor";
sfd.FileName = $"topic_{selectedTopic.Title.Replace(" ", "_")}_{DateTime.Now:yyyyMMdd}.ffor";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
// Собираем данные для экспорта
string exportData = "FFORUMF TOPIC EXPORT\n";
exportData += $"ID:{selectedTopic.Id}\n";
exportData += $"TITLE:{selectedTopic.Title}\n";
exportData += $"AUTHOR:{selectedTopic.Author}\n";
exportData += $"CREATED:{selectedTopic.Created}\n";
exportData += "CONTENT_BEGIN\n";
// В файл пишем зашифрованный контент
string encryptedContent = EncryptForFile(selectedTopic.Content);
exportData += encryptedContent + "\n";
exportData += "CONTENT_END\n";
// Сообщения (также зашифрованные)
foreach (var msg in selectedTopic.Messages)
{
string encryptedMessage = EncryptForFile(msg.Text);
exportData += $"MESSAGE:{msg.Id}|{msg.Author}|{msg.Time}|{encryptedMessage}\n";
}
// Сохраняем файл
File.WriteAllText(sfd.FileName, exportData);
AddLog($"Тема экспортирована в: {Path.GetFileName(sfd.FileName)}");
MessageBox.Show("Тема успешно экспортирована в .ffor файл!", "Успех",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
AddLog($"Ошибка экспорта: {ex.Message}");
MessageBox.Show($"Ошибка: {ex.Message}", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void CreateNewTopic(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(topicTitleBox.Text) ||
string.IsNullOrWhiteSpace(topicAuthorBox.Text) ||
string.IsNullOrWhiteSpace(topicContentBox.Text))
{
MessageBox.Show("Заполните все поля!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ForumTopic newTopic = new ForumTopic
{
Id = Guid.NewGuid().ToString(),
Title = topicTitleBox.Text,
Author = topicAuthorBox.Text,
Content = topicContentBox.Text, // В интерфейсе - обычный текст
Created = DateTime.Now
};
topics.Add(newTopic);
// Очищаем форму
topicTitleBox.Clear();
topicAuthorBox.Clear();
topicContentBox.Clear();
UpdateTopicsList();
AddLog($"Создана новая тема: {newTopic.Title}");
MessageBox.Show("Тема создана!", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void CreateBackup(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "FFOR Backup|*.ffor";
sfd.FileName = $"forum_backup_{DateTime.Now:yyyyMMdd_HHmmss}.ffor";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
string backupData = "FFORUMF BACKUP v2.0\n";
backupData += $"DATE:{DateTime.Now}\n";
backupData += $"TOPICS:{topics.Count}\n";
backupData += "ENCRYPTED:YES\n";
foreach (var topic in topics)
{
backupData += $"TOPIC_BEGIN\n";
backupData += $"TITLE:{topic.Title}\n";
backupData += $"AUTHOR:{topic.Author}\n";
backupData += $"CREATED:{topic.Created}\n";
// Контент шифруем только для файла
string encryptedContent = EncryptForFile(topic.Content);
backupData += $"CONTENT:{encryptedContent}\n";
foreach (var msg in topic.Messages)
{
string encryptedMessage = EncryptForFile(msg.Text);
backupData += $"MSG:{msg.Author}|{msg.Time}|{encryptedMessage}\n";
}
backupData += $"TOPIC_END\n";
}
File.WriteAllText(sfd.FileName, backupData);
AddLog($"Создан бэкап: {Path.GetFileName(sfd.FileName)}");
MessageBox.Show("Бэкап создан успешно! Данные зашифрованы.", "Резервная копия",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
AddLog($"Ошибка создания бэкапа: {ex.Message}");
MessageBox.Show($"Ошибка: {ex.Message}", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void SaveLogs(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Текстовые файлы|*.txt|Все файлы|*.*";
sfd.FileName = $"forum_logs_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
using (StreamWriter sw = new StreamWriter(sfd.FileName))
{
foreach (var item in logListBox.Items)
{
sw.WriteLine(item.ToString());
}
}
AddLog($"Логи сохранены в: {Path.GetFileName(sfd.FileName)}");
MessageBox.Show("Логи успешно сохранены!", "Успех",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка сохранения: {ex.Message}", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
public void AddLog(string message)
{
try
{
if (logListBox != null && !logListBox.IsDisposed)
{
if (logListBox.InvokeRequired)
{
logListBox.Invoke(new Action(AddLog), message);
}
else
{
string logEntry = $"[{DateTime.Now:HH:mm:ss}] {message}";
logListBox.Items.Add(logEntry);
logListBox.TopIndex = logListBox.Items.Count - 1;
}
}
}
catch { }
}
private void StartServer(Label statusLabel, Label ipLabel, Label clientsLabel, Button startBtn)
{
if (isRunning) return;
try
{
server = new TcpListener(IPAddress.Any, port);
server.Start();
isRunning = true;
serverThread = new Thread(() =>
{
while (isRunning)
{
try
{
TcpClient client = server.AcceptTcpClient();
string clientIP = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
ClientHandler handler = new ClientHandler(client, this);
clients.Add(handler);
Thread clientThread = new Thread(new ThreadStart(handler.Process));
clientThread.Start();
this.Invoke(new Action(() => {
clientsLabel.Text = $"Клиентов: {clients.Count}";
}));
AddLog($"Новое подключение: {clientIP}");
}
catch { }
}
});
serverThread.Start();
statusLabel.Text = "СЕРВЕР ОНЛАЙН";
statusLabel.ForeColor = Color.Lime;
string localIP = GetLocalIPAddress();
if (showIP)
{
ipLabel.Text = $"IP: {localIP}:{port}";
}
startBtn.Enabled = false;
AddLog($"Хост запущен на {localIP}:{port}");
MessageBox.Show($"Хост запущен!\n\nIP для подключения: {localIP}:{port}",
"FForumF Хост", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
AddLog($"Ошибка запуска сервера: {ex.Message}");
MessageBox.Show($"Ошибка запуска: {ex.Message}", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void StopServer(Label statusLabel, Label ipLabel, Label clientsLabel, Button startBtn)
{
if (!isRunning) return;
try
{
isRunning = false;
server.Stop();
foreach (var client in clients)
{
client.Close();
}
clients.Clear();
statusLabel.Text = "СЕРВЕР ОФФЛАЙН";
statusLabel.ForeColor = Color.Red;
ipLabel.Text = "IP: Сервер не запущен";
clientsLabel.Text = "Клиентов: 0";
startBtn.Enabled = true;
AddLog("Хост остановлен");
// Предлагаем скачать бэкап
if (topics.Count > 0)
{
var result = MessageBox.Show("Хотите сохранить резервную копию всех тем перед выходом?",
"Бэкап", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
CreateBackupOnStop();
}
}
}
catch (Exception ex)
{
AddLog($"Ошибка остановки сервера: {ex.Message}");
}
}
private void CreateBackupOnStop()
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "FFOR Backup|*.ffor";
sfd.FileName = $"forum_stop_backup_{DateTime.Now:yyyyMMdd_HHmmss}.ffor";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
string backupData = "FFORUMF STOP BACKUP\n";
backupData += $"DATE:{DateTime.Now}\n";
backupData += $"TOPICS:{topics.Count}\n";
foreach (var topic in topics)
{
string encryptedTitle = EncryptForFile(topic.Title);
backupData += $"TOPIC:{encryptedTitle}|{topic.Author}|{topic.Created}\n";
}
File.WriteAllText(sfd.FileName, backupData);
AddLog($"Бэкап при остановке создан: {Path.GetFileName(sfd.FileName)}");
MessageBox.Show("Бэкап создан успешно!", "Резервная копия",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
AddLog($"Ошибка создания бэкапа: {ex.Message}");
}
}
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (isRunning)
{
var result = MessageBox.Show("Хост все еще работает. Остановить и выйти?",
"Подтверждение", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
if (topics.Count > 0)
{
try
{
string autoBackup = $"auto_backup_{DateTime.Now:yyyyMMdd_HHmmss}.ffor";
string backupData = "AUTO BACKUP\n";
foreach (var topic in topics)
{
backupData += $"TOPIC:{topic.Title}\n";
}
File.WriteAllText(autoBackup, backupData);
AddLog($"Авто-бэкап создан: {autoBackup}");
}
catch { }
}
logoTimer?.Stop();
isRunning = false;
server?.Stop();
}
else
{
e.Cancel = true;
}
}
}
private string GetLocalIPAddress()
{
try
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
}
catch { }
return "127.0.0.1";
}
public string EncryptData(string data) => EncryptForFile(data);
public string DecryptData(string data) => DecryptFromFile(data);
// Класс обработки клиентов
private class ClientHandler
{
private TcpClient client;
private NetworkStream stream;
private MainForm mainForm;
public ClientHandler(TcpClient tcpClient, MainForm form)
{
client = tcpClient;
stream = client.GetStream();
mainForm = form;
}
public void Process()
{
try
{
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
mainForm.AddLog($"Запрос от клиента: {request.Substring(0, Math.Min(50, request.Length))}");
string response = "OK";
byte[] responseData = Encoding.UTF8.GetBytes(response);
stream.Write(responseData, 0, responseData.Length);
}
}
catch
{
// Клиент отключился
}
finally
{
Close();
}
}
public void Close()
{
try
{
stream?.Close();
client?.Close();
}
catch { }
}
}
}
// Форма для ответов на темы
public class ReplyForm : Form
{
private ForumTopic topic;
private MainForm mainForm;
private TextBox authorBox;
private RichTextBox messageBox;
public ReplyForm(ForumTopic topic, MainForm mainForm)
{
this.topic = topic;
this.mainForm = mainForm;
InitializeForm();
}
private void InitializeForm()
{
this.Text = $"Ответ в тему: {topic.Title}";
this.Size = new Size(700, 500);
this.StartPosition = FormStartPosition.CenterScreen;
this.BackColor = Color.FromArgb(15, 15, 15);
// Заголовок
Label titleLabel = new Label();
titleLabel.Text = $"Ответ в: {topic.Title}";
titleLabel.Font = new Font("Consolas", 14, FontStyle.Bold);
titleLabel.ForeColor = Color.Cyan;
titleLabel.Location = new Point(20, 20);
titleLabel.Size = new Size(650, 30);
// Автор
Label authorLabel = new Label();
authorLabel.Text = "Ваше имя:";
authorLabel.ForeColor = Color.White;
authorLabel.Location = new Point(20, 70);
authorBox = new TextBox();
authorBox.Size = new Size(300, 25);
authorBox.Location = new Point(120, 67);
authorBox.BackColor = Color.Black;
authorBox.ForeColor = Color.Lime;
authorBox.Font = new Font("Consolas", 10);
// Сообщение
Label messageLabel = new Label();
messageLabel.Text = "Сообщение:";
messageLabel.ForeColor = Color.White;
messageLabel.Location = new Point(20, 120);
messageBox = new RichTextBox();
messageBox.Size = new Size(650, 250);
messageBox.Location = new Point(20, 150);
messageBox.BackColor = Color.Black;
messageBox.ForeColor = Color.Lime;
messageBox.Font = new Font("Consolas", 10);
// Кнопки
Button sendBtn = new Button();
sendBtn.Text = "ОТПРАВИТЬ ОТВЕТ";
sendBtn.Size = new Size(200, 40);
sendBtn.Location = new Point(150, 420);
sendBtn.BackColor = Color.FromArgb(0, 80, 0);
sendBtn.ForeColor = Color.White;
sendBtn.Click += SendReply;
Button cancelBtn = new Button();
cancelBtn.Text = "ОТМЕНА";
cancelBtn.Size = new Size(200, 40);
cancelBtn.Location = new Point(370, 420);
cancelBtn.Click += (s, e) => this.DialogResult = DialogResult.Cancel;
this.Controls.AddRange(new Control[] {
titleLabel,
authorLabel, authorBox,
messageLabel, messageBox,
sendBtn, cancelBtn
});
}
private void SendReply(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(authorBox.Text) ||
string.IsNullOrWhiteSpace(messageBox.Text))
{
MessageBox.Show("Заполните имя и сообщение!", "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
ForumMessage newMessage = new ForumMessage
{
Id = Guid.NewGuid().ToString(),
Author = authorBox.Text,
Text = messageBox.Text, // Обычный текст в интерфейсе
Time = DateTime.Now
};
topic.Messages.Add(newMessage);
this.DialogResult = DialogResult.OK;
this.Close();
}
}
// Форма просмотра темы (БЕЗ ШИФРОВАНИЯ в интерфейсе)
public class TopicViewForm : Form
{
private ForumTopic topic;
private MainForm mainForm;
private ListBox messagesList;
public TopicViewForm(ForumTopic topic, MainForm mainForm)
{
this.topic = topic;
this.mainForm = mainForm;
InitializeForm();
}
private void InitializeForm()
{
this.Text = $"Тема: {topic.Title}";
this.Size = new Size(900, 700);
this.StartPosition = FormStartPosition.CenterScreen;
this.BackColor = Color.FromArgb(15, 15, 15);
// Заголовок
Label titleLabel = new Label();
titleLabel.Text = topic.Title;
titleLabel.Font = new Font("Consolas", 16, FontStyle.Bold);
titleLabel.ForeColor = Color.Cyan;
titleLabel.Location = new Point(20, 20);
titleLabel.Size = new Size(850, 40);
// Информация
Label infoLabel = new Label();
infoLabel.Text = $"Автор: {topic.Author} | Создано: {topic.Created:dd.MM.yyyy HH:mm} | Ответов: {topic.Messages.Count}";
infoLabel.Font = new Font("Consolas", 10);
infoLabel.ForeColor = Color.LightGray;
infoLabel.Location = new Point(20, 70);
// Содержание (ОБЫЧНЫЙ ТЕКСТ - не шифрованный!)
RichTextBox contentBox = new RichTextBox();
contentBox.Text = topic.Content; // Прямой текст
contentBox.Size = new Size(850, 150);
contentBox.Location = new Point(20, 100);
contentBox.BackColor = Color.Black;
contentBox.ForeColor = Color.White;
contentBox.Font = new Font("Consolas", 10);
contentBox.ReadOnly = true;
// Ответы
Label repliesLabel = new Label();
repliesLabel.Text = "Ответы:";
repliesLabel.Font = new Font("Consolas", 12, FontStyle.Bold);
repliesLabel.ForeColor = Color.White;
repliesLabel.Location = new Point(20, 270);
messagesList = new ListBox();
messagesList.Size = new Size(850, 300);
messagesList.Location = new Point(20, 300);
messagesList.BackColor = Color.Black;
messagesList.ForeColor = Color.Lime;
messagesList.Font = new Font("Consolas", 9);
UpdateMessagesList();
// Кнопки
Button replyBtn = new Button();
replyBtn.Text = "ОТВЕТИТЬ";
replyBtn.Size = new Size(200, 40);
replyBtn.Location = new Point(20, 620);
replyBtn.Click += (s, e) =>
{
ReplyForm replyForm = new ReplyForm(topic, mainForm);
if (replyForm.ShowDialog() == DialogResult.OK)
{
UpdateMessagesList();
}
};
Button closeBtn = new Button();
closeBtn.Text = "ЗАКРЫТЬ";
closeBtn.Size = new Size(200, 40);
closeBtn.Location = new Point(670, 620);
closeBtn.Click += (s, e) => this.Close();
this.Controls.AddRange(new Control[] {
titleLabel, infoLabel, contentBox,
repliesLabel, messagesList,
replyBtn, closeBtn
});
}
private void UpdateMessagesList()
{
messagesList.Items.Clear();
foreach (var msg in topic.Messages.OrderBy(m => m.Time))
{
// Прямой текст - не дешифрованный!
messagesList.Items.Add($"[{msg.Time:HH:mm}] {msg.Author}: {msg.Text}");
}
}
}
}
Form4.Designer.cs
namespace FForumF
{
partial class MainForm
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form4";
}
#endregion
}
}