Набросал тестовую реализацию теории, по итогу из исходных координат предметов создаем шаблон сдвигов предметов, после чего накладываем шаблон на координату позиции курсора игрока, вечером проверю работает ли это на практике, тогда можно будет начать писать код создания шаблона из слота и помещение его в спец таблицу где будут лежать шаблоны которые игроки смогут загружать.
public Action CmdLoadTemplate(int client, int args)
{
float vPos[3][3], vSpawnPos[3][3], vTemplatePos[3][3], vMainOffsetPos[3];
// ИСХОДНЫЕ КООРДИНАТЫ ПРЕДМЕТОВ
// координата позииции предмета 1
vPos[0][0] = 0.0;
vPos[0][1] = 0.0;
vPos[0][2] = 0.0;
// координата позииции предмета 2
vPos[1][0] = 0.0;
vPos[1][1] = 0.0;
vPos[1][2] = 0.0;
// координата позииции предмета 3
vPos[2][0] = 0.0;
vPos[2][1] = 0.0;
vPos[2][2] = 0.0;
PrintToChat(client, "Входные координаты:: vPos[0] %f %f %f, vPos[1] %f %f %f, vPos[2] %f %f %f", vPos[0][0], vPos[0][1], vPos[0][2], vPos[1][0], vPos[1][1], vPos[1][2], vPos[2][0], vPos[2][1], vPos[2][2]);
// СОЗДАНИЕ ШАБЛОНА
// Берем координату первого предмета за базовую и вычитаем ее из всех остальных, а координату первого считаем как нулевую точку (тоесть первый предмет будет рождатся на позиции курсора).
vMainOffsetPos[0] = vPos[0][0];
vMainOffsetPos[1] = vPos[0][1];
vMainOffsetPos[2] = vPos[0][2];
// Координату первого обнуляем.
vTemplatePos[0][0] = 0.0;
vTemplatePos[0][1] = 0.0;
vTemplatePos[0][2] = 0.0;
// Координата шаблона следующих предметов будет: координата предмета вычесть координату первого предмета.
// Вычисляем координату сдвига второго и третьего предмета
SubtractVectors(vPos[1], vMainOffsetPos, vTemplatePos[1]);
SubtractVectors(vPos[2], vMainOffsetPos, vTemplatePos[2]);
PrintToChat(client, "Шаблон:: vTemplatePos[0] %f %f %f, vTemplatePos[1] %f %f %f, vTemplatePos[2] %f %f %f", vTemplatePos[0][0], vTemplatePos[0][1], vTemplatePos[0][2], vTemplatePos[1][0], vTemplatePos[1][1], vTemplatePos[1][2], vTemplatePos[2][0], vTemplatePos[2][1], vTemplatePos[2][2]);
// РОЖДЕНИЕ ИЗ ШАБЛОНА
// Берем место куда смотрит курсор
float vClientEyePos[3], vClientEyeAng[3], vCursorPos[3];
GetClientEyePosition(client, vClientEyePos);
GetClientEyeAngles(client, vClientEyeAng);
Handle trace = TR_TraceRayFilterEx( vClientEyePos, vClientEyeAng, MASK_SOLID_BRUSHONLY, RayType_Infinite, TraceEntityFilterPlayers );
if(TR_DidHit( trace ))
{
TR_GetEndPosition( vCursorPos, trace );
// Накладываем на шаблонные координаты сдвигов позицию курсора
AddVectors(vCursorPos, vTemplatePos[0], vSpawnPos[0]);
AddVectors(vCursorPos, vTemplatePos[1], vSpawnPos[1]);
AddVectors(vCursorPos, vTemplatePos[2], vSpawnPos[2]);
PrintToChat(client, "Координаты спавна из шаблона:: vSpawnPos[0] %f %f %f, vSpawnPos[1] %f %f %f, vSpawnPos[2] %f %f %f", vSpawnPos[0][0], vSpawnPos[0][1], vSpawnPos[0][2], vSpawnPos[1][0], vSpawnPos[1][1], vSpawnPos[1][2], vSpawnPos[2][0], vSpawnPos[2][1], vSpawnPos[2][2]);
}
}
public bool TraceEntityFilterPlayers(int entity, int contentsMask, any data )
{
return entity > MaxClients && entity != data;
}