Участник
Пользователь
iPlague
♿️
- Сообщения
- 230
- Реакции
- 130
- Помог
- 2 раз(а)
Для полноценного плагина, пожалуй, не годится, но как наработка сойдёт.
У меня есть идея фикс - написать автоматическую расстановку спавнов по карте для таких модов как gungame, csdm. Знаю, что это довольно сложно, поэтому решил начать с малого - поставил перед собой задачу написать плагин, который будет автоматически добавлять спавны, если на карте их изначально меньше 16 (cs_assault, cs_militia, cs_estate, de_nuke и т.д.). Знаете, даже кое что получилось.
1. Для начала подсчитал количество спавнов, определил сколько нужно добавить. Записал ID и координаты каждого спавна.
2. Для наглядности поставил модельки
3. Прошёлся циклом по полученным спавнам, вокруг каждого из них искал свободное место по такой схеме:
Попутно выводил в консоль разную информацию:
5. Проверил заново количество спавнов
Результат меня на данном этапе вполне устраивает. Проверял на таких картах: cs_assault, cs_office, cs_italy, cs_estate, cs_militia (эти карты имеют по 10 слотов на команду, de_ карты в основном 16-20 слотов) , на парочке своих карт, где специально расставлял 8-10 спавнов среди различных брашей и энтити.
Вот что вышло.
Собственно, сам код:
Следующие этапы:
Спасибо за внимание.
У меня есть идея фикс - написать автоматическую расстановку спавнов по карте для таких модов как gungame, csdm. Знаю, что это довольно сложно, поэтому решил начать с малого - поставил перед собой задачу написать плагин, который будет автоматически добавлять спавны, если на карте их изначально меньше 16 (cs_assault, cs_militia, cs_estate, de_nuke и т.д.). Знаете, даже кое что получилось.
1. Для начала подсчитал количество спавнов, определил сколько нужно добавить. Записал ID и координаты каждого спавна.
2. Для наглядности поставил модельки
3. Прошёлся циклом по полученным спавнам, вокруг каждого из них искал свободное место по такой схеме:
Попутно выводил в консоль разную информацию:
- номер каждого проверяемого спавна
- наличие энтити вокруг этого спавна
- в случае успеха - информацию о новом созданном спавне
5. Проверил заново количество спавнов
Результат меня на данном этапе вполне устраивает. Проверял на таких картах: cs_assault, cs_office, cs_italy, cs_estate, cs_militia (эти карты имеют по 10 слотов на команду, de_ карты в основном 16-20 слотов) , на парочке своих карт, где специально расставлял 8-10 спавнов среди различных брашей и энтити.
Вот что вышло.
Код:
#include <amxmodx>
#include <reapi>
#include <engine>
#include <fakemeta>
#define TT_MDL "models/player/leet/leet.mdl"
#define CT_MDL "models/player/gign/gign.mdl"
new g_iModel_ct, g_iModel_tt;
new g_SpawnsNum[3];
new g_SpawnsNumNeeded[3];
new g_EntCT[32], g_EntTT[32];
new Float:coordsCT[32][3];
new Float:coordsTT[32][3];
new const Float:point[8][2] = { {0.0, -1.0} , // we will try to find space in 2D
{1.0, -1.0} , // 8 point around each spawn
{1.0, 0.0} , // in all X Y directions
{1.0, 1.0} ,
{0.0, 1.0} ,
{-1.0, 1.0} ,
{0.0, -1.0} ,
{-1.0, -1.0} };
public plugin_init(){
get_spawns_num();
register_plugin("ASP", "1.0.0", "iPlague");
register_clcmd("test", "test_spawns");
register_srvcmd("test", "test_spawns");
register_clcmd("check", "check_spawns");
register_clcmd("check_tt_spawn", "check_tt_spawn");
register_clcmd("check_ct_spawn", "check_ct_spawn");
}
public plugin_precache(){
g_iModel_ct = precache_model(CT_MDL);
g_iModel_tt = precache_model(TT_MDL);
}
get_spawns_num(){
server_print("================= COUNT SPAWNS =================");
new Ent1 = NULLENT, numCT = 0;
while((Ent1 = rg_find_ent_by_class(Ent1, "info_player_start")) != 0){
g_EntCT[numCT] = Ent1;
new Float:forigin1[3]; get_entvar(g_EntCT[numCT], var_origin, forigin1);
set_entvar(g_EntCT[numCT], var_model, CT_MDL);
set_entvar(g_EntCT[numCT], var_modelindex, g_iModel_ct);
coordsCT[numCT][0] = forigin1[0];
coordsCT[numCT][1] = forigin1[1];
coordsCT[numCT][2] = forigin1[2];
server_print("%d. CT spawn ID: %d | Origins: %.0f %.0f %.0f", numCT + 1, g_EntCT[numCT], forigin1[0],forigin1[1],forigin1[2]);
numCT++;
}
Ent1 = NULLENT; new numTT = 0;
while((Ent1 = rg_find_ent_by_class(Ent1, "info_player_deathmatch")) != 0){ // Ищем спавны ТТ, записываем координаты, пишем инфу в консоль.
g_EntTT[numTT] = Ent1;
new Float:forigin1[3]; get_entvar(g_EntTT[numTT], var_origin, forigin1);
set_entvar(g_EntTT[numTT], var_model, TT_MDL);
set_entvar(g_EntTT[numTT], var_modelindex, g_iModel_tt);
coordsTT[numTT][0] = forigin1[0];
coordsTT[numTT][1] = forigin1[1];
coordsTT[numTT][2] = forigin1[2];
server_print("%d. TT spawn ID: %d | Origins: %.0f %.0f %.0f", numTT + 1, g_EntTT[numTT], forigin1[0],forigin1[1],forigin1[2]);
numTT++;
}
g_SpawnsNum[1] = numTT; g_SpawnsNum[2] = numCT;
g_SpawnsNumNeeded[1] = max(16 - g_SpawnsNum[1], 0);
g_SpawnsNumNeeded[2] = max(16 - g_SpawnsNum[2], 0);
server_print("Totaly found CT spawns: %d | TT spawns: %d", g_SpawnsNum[1], g_SpawnsNum[2]);
server_print("SO THAT WE NEED TO ADD %d CT & %d TT SPAWNS", g_SpawnsNumNeeded[1], g_SpawnsNumNeeded[2]);
}
public test_spawns(){
server_print("================= LETS TRY =================");
static Float:mins[3],Float:vec[3];
mins[0] = mins[1] = -24.0;
mins[2] = -40.0;
new num = g_SpawnsNum[1];
for(new i = 0; i < num; i++){// for each TT spawn
if(g_SpawnsNumNeeded[1] <= 0){
server_print("WE ALREADY DON'T NEED TO ADD TT SPAWNS");
server_print("================== FINISH ====================");
break;
}
server_print("TRY TO FIND FREE SPACE AROUND %dth SPAWN^n", i + 1);
vec[2] = coordsTT[i][2];
for (new j; j < sizeof point; j++){ // for each direction check free space around %i spawn
vec[0] = coordsTT[i][0] - 6.0 * mins[0] * point[j][0];
vec[1] = coordsTT[i][1] - 6.0 * mins[1] * point[j][1];
if(is_place_ok(vec, 48.0) && is_place_in_side(g_EntTT[i], coordsTT[i], vec)){
server_print("WE ADD 1 SPAWN AROUND %dth TT SPAWN^n", i+1);
new ent_T = rg_create_entity("info_player_deathmatch", false);
//if(!is_nullent(ent_T)){
set_entvar(ent_T, var_model, TT_MDL);
set_entvar(ent_T, var_modelindex, g_iModel_tt);
engfunc(EngFunc_SetOrigin, ent_T, vec);
set_entvar(ent_T, var_renderfx, kRenderFxGlowShell);
set_entvar(ent_T, var_rendercolor, {255.0,0.0,0.0});
set_entvar(ent_T, var_rendermode, kRenderNormal);
set_entvar(ent_T, var_renderamt, 32);
g_SpawnsNumNeeded[1]--;
g_SpawnsNum[1]++;
g_EntTT[g_SpawnsNum[1] - 1] = ent_T;
coordsTT[g_SpawnsNum[1] - 1][0] = vec[0];
coordsTT[g_SpawnsNum[1] - 1][1] = vec[1];
coordsTT[g_SpawnsNum[1] - 1][2] = vec[2];
break; // for the 1th time we try to create only one spawn around each point
//}
}
}
}
num = g_SpawnsNum[2];
for(new i = 0; i < num; i++){// for each CT spawn
if(g_SpawnsNumNeeded[2] <= 0){
server_print("WE ALREADY DON'T NEED TO ADD CT SPAWNS");
server_print("================== FINISH ====================");
break;
}
server_print("TRY TO FIND FREE SPACE AROUND %dth SPAWN^n", i + 1);
vec[2] = coordsCT[i][2];
for (new j; j < sizeof point; j++){ // for each direction check free space around %i spawn
vec[0] = coordsCT[i][0] - 6.0 * mins[0] * point[j][0];
vec[1] = coordsCT[i][1] - 6.0 * mins[1] * point[j][1];
if(is_place_ok(vec, 48.0) && is_place_in_side(g_EntCT[i], coordsCT[i], vec)){
server_print("WE ADD 1 SPAWN AROUND %dth CT SPAWN^n", i+1);
new ent_CT = rg_create_entity("info_player_start", false);
//if(!is_nullent(ent_CT)){
set_entvar(ent_CT, var_model, CT_MDL);
set_entvar(ent_CT, var_modelindex, g_iModel_ct);
engfunc(EngFunc_SetOrigin, ent_CT, vec);
set_entvar(ent_CT, var_renderfx, kRenderFxGlowShell);
set_entvar(ent_CT, var_rendercolor, {0.0,0.0,255.0});
set_entvar(ent_CT, var_rendermode, kRenderNormal);
set_entvar(ent_CT, var_renderamt, 32);
g_SpawnsNumNeeded[2]--;
g_SpawnsNum[2]++;
g_EntCT[g_SpawnsNum[2] - 1] = ent_CT;
coordsCT[g_SpawnsNum[2] - 1][0] = vec[0];
coordsCT[g_SpawnsNum[2] - 1][1] = vec[1];
coordsCT[g_SpawnsNum[2] - 1][2] = vec[2];
break; // for the 1th time we try to create only one spawn around each point
//}
}
}
}
}
public check_spawns(id){
new Ent1 = NULLENT, numCT = 0, numTT = 0;
while((Ent1 = rg_find_ent_by_class(Ent1, "info_player_start")) != 0)
numCT++;
while((Ent1 = rg_find_ent_by_class(Ent1, "info_player_deathmatch")) != 0)
numTT++;
server_print("RESULT: WE FOUND %d TTs AND %d CTs SPAWNS", numCT, numCT);
}
new check_tt = 0;
public check_tt_spawn(id){
set_entvar(id, var_origin, coordsTT[check_tt]);
server_print("WE AT %d spawn", check_tt);
if(is_place_ok(coordsTT[check_tt], 48.0))
server_print("SPAWN %d IS OK", check_tt);
check_tt = (check_tt + 1) % (g_SpawnsNum[1]);
}
new check_ct = 0;
public check_ct_spawn(id){
set_entvar(id, var_origin, coordsCT[check_ct]);
server_print("WE AT %d spawn", check_ct);
if(is_place_ok(coordsCT[check_ct], 48.0))
server_print("SPAWN %d IS OK", check_tt);
check_ct = (check_ct + 1) % (g_SpawnsNum[2]);
}
stock bool:is_place_in_side(idUser, const Float:start[3], const Float:dest[3]){
engfunc(EngFunc_TraceLine, start, dest, 0, idUser, 0);
new Float:fraction; get_tr2(0, TR_flFraction, fraction);
if(fraction == 1.0)
return true;
return false;
}
stock bool:is_place_ok(const Float:forigin[3], Float:radius){
new Ent = NULLENT;
while((Ent = find_ent_in_sphere(Ent, forigin, radius)) != 0){
new szClassname[32]; get_entvar(Ent, var_classname, szClassname, 31);
if(equal(szClassname, "func_buyzone") || equal(szClassname, "func_hostage_rescue"))
continue;
server_print("WE FIND %s entity in radius %.0f units", szClassname, radius)
return false;
}
new tr = 0; engfunc(EngFunc_TraceHull, forigin, forigin, 0, HULL_HUMAN, 0, tr);
if(!get_tr2(tr, TR_StartSolid) && !get_tr2(tr, TR_AllSolid) && get_tr2(tr, TR_InOpen))
return true;
return false;
}
- пофиксить баги, которые удастся найти
- потестить на разных "сложных" картах
- попробовать расстановку спавнов по всей площади для симметричных карт, начну с аim_map.
Спасибо за внимание.