Enhance school creation functionality by introducing support for name sets in the API and UI. Update the catalog to include skills, traits, body attributes, needs, and name sets, improving character generation capabilities. Revise localization strings for better user guidance and update tests to validate the new name set functionality and ensure robustness in school creation processes.
ci / server (push) Failing after 3m45s
ci / client (push) Successful in 17s

This commit is contained in:
Leonid Pershin
2026-08-18 18:57:01 +03:00
parent 38afbcad36
commit e6182e0e45
56 changed files with 3706 additions and 9 deletions
+85
View File
@@ -0,0 +1,85 @@
namespace HSchool.People;
public readonly record struct StaffOpening(string RoomId, string Position);
public readonly record struct PupilSeat(string ClassId, string RoomId, int Year, string Letter);
/// <summary>
/// How many pupils and staff a map asks for. Classrooms are rooms with pupil slots; each one
/// becomes a roster class. Positions come from <see cref="RoomDef.Positions"/>, not the wire labels.
/// </summary>
public sealed class SchoolDemand
{
internal SchoolDemand(
IReadOnlyList<SchoolClass> classes,
IReadOnlyList<PupilSeat> seats,
IReadOnlyList<StaffOpening> staff)
{
Classes = classes;
Seats = seats;
Staff = staff;
}
public IReadOnlyList<SchoolClass> Classes { get; }
public IReadOnlyList<PupilSeat> Seats { get; }
public IReadOnlyList<StaffOpening> Staff { get; }
public static SchoolDemand From(DefCatalog catalog, MapLayout map)
{
var classrooms = new List<(RoomNode Room, int Slots)>();
var staff = new List<StaffOpening>();
foreach (var room in map.Rooms)
{
var slots = PupilSlotsOf(catalog, room);
if (slots > 0)
{
classrooms.Add((room, slots));
}
if (catalog.Rooms.TryGetValue(room.Def, out var def))
{
foreach (var position in def.Positions)
{
staff.Add(new StaffOpening(room.Id, position));
}
}
}
const string letters = "АБВГДЕЖЗИКЛМНОПРСТУФХЦЧШЩЭЮЯ";
var classes = new SchoolClass[classrooms.Count];
var seats = new List<PupilSeat>();
for (var i = 0; i < classrooms.Count; i++)
{
var (room, capacity) = classrooms[i];
var year = (i % 11) + 1;
var letterIndex = i / 11;
var letter = letterIndex < letters.Length ? letters[letterIndex].ToString() : "?";
var classId = $"class-{room.Id}";
classes[i] = new SchoolClass(classId, year, letter, room.Id, capacity, []);
for (var seat = 0; seat < capacity; seat++)
{
seats.Add(new PupilSeat(classId, room.Id, year, letter));
}
}
return new SchoolDemand(classes, seats, staff);
}
private static int PupilSlotsOf(DefCatalog catalog, RoomNode room)
{
var pupilSlots = 0L;
foreach (var fill in room.Slots)
{
var count = fill.Count < 1 ? 1 : Math.Min(fill.Count, byte.MaxValue);
if (catalog.Things.TryGetValue(fill.Thing, out var thing) && thing.PupilSlots > 0)
{
pupilSlots += (long)thing.PupilSlots * count;
}
}
return (int)Math.Clamp(pupilSlots, 0, ushort.MaxValue);
}
}