CCCPaste

8632b088dc756

// ==================== РЕАЛИЗАЦИЯ СИСТЕМЫ СЦЕН ====================

// Создание сцены
stock EventEngine:CreateScene(event_id, const name[], task_min, task_max, flags)
{
if (g_EventEngine_SceneCount >= MAX_SCENES)
{
printf("[EventEngine] Ошибка: Достигнут лимит сцен (%d)", MAX_SCENES);
return EVENT_INVALID_VALUE;
}

new scene_id = g_EventEngine_SceneCount;

g_EventEngine_Scenes[scene_id][E_SCENE_ID] = scene_id;
g_EventEngine_Scenes[scene_id][E_SCENE_EVENT_ID] = event_id;
format(g_EventEngine_Scenes[scene_id][E_SCENE_NAME], 32, name);
g_EventEngine_Scenes[scene_id][E_SCENE_TASK_MIN] = task_min;
g_EventEngine_Scenes[scene_id][E_SCENE_TASK_MAX] = task_max;
g_EventEngine_Scenes[scene_id][E_SCENE_FLAGS] = flags;
g_EventEngine_Scenes[scene_id][E_SCENE_ENTITY_COUNT] = 0;
g_EventEngine_Scenes[scene_id][E_SCENE_ZONE_ID] = EVENT_INVALID_VALUE;
g_EventEngine_Scenes[scene_id][E_SCENE_ACTIVE] = false;

g_EventEngine_SceneCount++;

printf("[EventEngine] Создана сцена '%s' (ID: %d, Задания: %d-%d)", name, scene_id, task_min, task_max);
return scene_id;
}

// Добавление сущности в сцену
stock EventEngine:AddSceneEntity(scene_id, E_SCENE_ENTITY_TYPE:type, Float:x, Float:y, Float:z, ...)
{
if (scene_id < 0 || scene_id >= g_EventEngine_SceneCount)
return false;

if (g_EventEngine_Scenes[scene_id][E_SCENE_ENTITY_COUNT] >= MAX_SCENE_ENTITIES)
{
printf("[EventEngine] Ошибка: Достигнут лимит сущностей в сцене %d", scene_id);
return false;
}

new entity_index = g_EventEngine_Scenes[scene_id][E_SCENE_ENTITY_COUNT];
new entity[E_SCENE_ENTITY];

entity[E_ENTITY_TYPE] = _:type;
entity[E_ENTITY_ID] = EVENT_INVALID_VALUE; // Будет установлен при активации
entity[E_ENTITY_X] = x;
entity[E_ENTITY_Y] = y;
entity[E_ENTITY_Z] = z;

// Обработка дополнительных параметров в зависимости от типа
switch (type)
{
case SCENE_ENTITY_OBJECT:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // modelid
entity[E_ENTITY_RX] = Float:getarg(4);
entity[E_ENTITY_RY] = Float:getarg(5);
entity[E_ENTITY_RZ] = Float:getarg(6);
}

case SCENE_ENTITY_VEHICLE:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // modelid
entity[E_ENTITY_RZ] = Float:getarg(4); // rotation
}

case SCENE_ENTITY_NPC, SCENE_ENTITY_ACTOR:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // skin/model
entity[E_ENTITY_RZ] = Float:getarg(4); // rotation
}

case SCENE_ENTITY_SOUND:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // sound name (через хэш)
entity[E_ENTITY_RADIUS] = Float:getarg(4); // радиус звука
}

case SCENE_ENTITY_WEATHER:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // weather id
}

case SCENE_ENTITY_TIME:
{
entity[E_ENTITY_REFERENCE] = getarg(3); // hour
entity[E_ENTITY_EXTRA_1] = getarg(4); // minute
}

case SCENE_ENTITY_ZONE:
{
entity[E_ENTITY_RADIUS] = Float:getarg(3); // радиус зоны
}
}

// Копируем сущность в сцену
g_EventEngine_Scenes[scene_id][E_SCENE_ENTITIES][entity_index] = entity;
g_EventEngine_Scenes[scene_id][E_SCENE_ENTITY_COUNT]++;

printf("[EventEngine] Добавлена сущность типа %d в сцену %d", _:type, scene_id);
return true;
}

// Активация сцены для игрока
stock EventEngine:ActivatePlayerScene(playerid, scene_id)
{
if (scene_id < 0 || scene_id >= g_EventEngine_SceneCount)
return false;

if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] >= MAX_PLAYER_SCENES)
{
printf("[EventEngine] Ошибка: У игрока %d достигнут лимит активных сцен", playerid);
return false;
}

// Проверяем, не активирована ли уже сцена
if (EventEngine:IsSceneActiveForPlayer(playerid, scene_id))
return true;

new scene[E_SCENE_DATA];
scene = g_EventEngine_Scenes[scene_id];

// Сохраняем исходные настройки игрока при первой активации сцены
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] == 0)
{
g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_WEATHER] = GetPlayerWeather(playerid);
g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_TIME] = GetPlayerTime(playerid);
g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_INTERIOR] = GetPlayerInterior(playerid);
g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_WORLD] = GetPlayerVirtualWorld(playerid);
}

// Создаем сущности сцены
for (new i = 0; i < scene[E_SCENE_ENTITY_COUNT]; i++)
{
new entity[E_SCENE_ENTITY] = scene[E_SCENE_ENTITIES][i];

switch (E_SCENE_ENTITY_TYPE:entity[E_ENTITY_TYPE])
{
case SCENE_ENTITY_OBJECT:
{
new object_id = CreateDynamicObject(
entity[E_ENTITY_REFERENCE],
entity[E_ENTITY_X], entity[E_ENTITY_Y], entity[E_ENTITY_Z],
entity[E_ENTITY_RX], entity[E_ENTITY_RY], entity[E_ENTITY_RZ],
.worldid = playerid, // Индивидуальный мир для игрока
.interiorid = GetPlayerInterior(playerid)
);
entity[E_ENTITY_ID] = object_id;
}

case SCENE_ENTITY_VEHICLE:
{
new vehicle_id = CreateVehicle(
entity[E_ENTITY_REFERENCE],
entity[E_ENTITY_X], entity[E_ENTITY_Y], entity[E_ENTITY_Z],
entity[E_ENTITY_RZ],
-1, -1, -1, 0 // Прозрачные цвета
);
SetVehicleVirtualWorld(vehicle_id, playerid + 1000); // Индивидуальный виртуальный мир
entity[E_ENTITY_ID] = vehicle_id;
}

case SCENE_ENTITY_NPC:
{
// Создание NPC в индивидуальном мире
new npc_id = NPC_Create(
entity[E_ENTITY_REFERENCE],
entity[E_ENTITY_X], entity[E_ENTITY_Y], entity[E_ENTITY_Z],
entity[E_ENTITY_RZ],
.worldid = playerid + 1000
);
entity[E_ENTITY_ID] = npc_id;
}

case SCENE_ENTITY_SOUND:
{
// Воспроизведение 3D звука
Sound:Play3D(
entity[E_ENTITY_REFERENCE], // Имя звукового файла
entity[E_ENTITY_X], entity[E_ENTITY_Y], entity[E_ENTITY_Z],
.min_distance = 5.0,
.max_distance = entity[E_ENTITY_RADIUS],
.initiator_system = SOUND_SYSTEM_EVENT_SCENE
);
}

case SCENE_ENTITY_WEATHER:
{
SetPlayerWeather(playerid, entity[E_ENTITY_REFERENCE]);
}

case SCENE_ENTITY_TIME:
{
SetPlayerTime(playerid, entity[E_ENTITY_REFERENCE], entity[E_ENTITY_EXTRA_1]);
}

case SCENE_ENTITY_INTERIOR:
{
SetPlayerInterior(playerid, entity[E_ENTITY_REFERENCE]);
}
}

// Сохраняем обновленную сущность
g_EventEngine_Scenes[scene_id][E_SCENE_ENTITIES][i] = entity;
}

// Добавляем сцену в список активных сцен игрока
g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]] = scene_id;
g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]++;

g_EventEngine_Scenes[scene_id][E_SCENE_ACTIVE] = true;

// Вызываем callback активации
if (funcidx("OnPlayerSceneActivate") != -1)
{
CallLocalFunction("OnPlayerSceneActivate", "ii", playerid, scene_id);
}

printf("[EventEngine] Активирована сцена %d для игрока %d", scene_id, playerid);
return true;
}

// Деактивация сцены для игрока
stock EventEngine:DeactivatePlayerScene(playerid, scene_id)
{
if (!EventEngine:IsSceneActiveForPlayer(playerid, scene_id))
return true;

new scene[E_SCENE_DATA];
scene = g_EventEngine_Scenes[scene_id];

// Удаляем сущности сцены
for (new i = 0; i < scene[E_SCENE_ENTITY_COUNT]; i++)
{
new entity[E_SCENE_ENTITY] = scene[E_SCENE_ENTITIES][i];

switch (E_SCENE_ENTITY_TYPE:entity[E_ENTITY_TYPE])
{
case SCENE_ENTITY_OBJECT:
{
if (entity[E_ENTITY_ID] != EVENT_INVALID_VALUE)
{
DestroyDynamicObject(entity[E_ENTITY_ID]);
}
}

case SCENE_ENTITY_VEHICLE:
{
if (entity[E_ENTITY_ID] != EVENT_INVALID_VALUE)
{
DestroyVehicle(entity[E_ENTITY_ID]);
}
}

case SCENE_ENTITY_NPC:
{
if (entity[E_ENTITY_ID] != EVENT_INVALID_VALUE)
{
NPC_Destroy(entity[E_ENTITY_ID]);
}
}

case SCENE_ENTITY_SOUND:
{
Sound:Stop3D(entity[E_ENTITY_REFERENCE], entity[E_ENTITY_X], entity[E_ENTITY_Y], entity[E_ENTITY_Z]);
}

case SCENE_ENTITY_WEATHER:
{
// Восстанавливаем исходную погоду при удалении последней сцены
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] == 1)
{
SetPlayerWeather(playerid, g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_WEATHER]);
}
}

case SCENE_ENTITY_TIME:
{
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] == 1)
{
ResetPlayerTime(playerid);
}
}
}

// Сбрасываем ID сущности
entity[E_ENTITY_ID] = EVENT_INVALID_VALUE;
g_EventEngine_Scenes[scene_id][E_SCENE_ENTITIES][i] = entity;
}

// Удаляем сцену из списка активных
for (new i = 0; i < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]; i++)
{
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][i] == scene_id)
{
// Сдвигаем остальные сцены
for (new j = i; j < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] - 1; j++)
{
g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][j] =
g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][j + 1];
}
g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]--;
break;
}
}

g_EventEngine_Scenes[scene_id][E_SCENE_ACTIVE] = false;

// Вызываем callback деактивации
if (funcidx("OnPlayerSceneDeactivate") != -1)
{
CallLocalFunction("OnPlayerSceneDeactivate", "ii", playerid, scene_id);
}

printf("[EventEngine] Деактивирована сцена %d для игрока %d", scene_id, playerid);
return true;
}

// Автоматическое обновление сцен при смене задания
stock EventEngine:UpdatePlayerScenes(playerid, current_task)
{
printf("[EventEngine] Обновление сцен для игрока %d (задание: %d)", playerid, current_task);

// Деактивируем сцены, которые больше не подходят
for (new i = 0; i < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]; i++)
{
new scene_id = g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][i];
new scene[E_SCENE_DATA] = g_EventEngine_Scenes[scene_id];

if (current_task < scene[E_SCENE_TASK_MIN] || current_task > scene[E_SCENE_TASK_MAX])
{
if (scene[E_SCENE_FLAGS] & SCENE_FLAG_AUTO_DESTROY)
{
EventEngine:DeactivatePlayerScene(playerid, scene_id);
i--; // Уменьшаем счетчик т.к. массив сдвинулся
}
}
}

// Активируем подходящие сцены
for (new scene_id = 0; scene_id < g_EventEngine_SceneCount; scene_id++)
{
new scene[E_SCENE_DATA] = g_EventEngine_Scenes[scene_id];

// Проверяем, подходит ли сцена по заданию и мероприятию
if (scene[E_SCENE_EVENT_ID] == g_EventEngine_ActiveEvent &&
current_task >= scene[E_SCENE_TASK_MIN] &&
current_task <= scene[E_SCENE_TASK_MAX] &&
!EventEngine:IsSceneActiveForPlayer(playerid, scene_id))
{
EventEngine:ActivatePlayerScene(playerid, scene_id);
}
}
}

// Проверка активности сцены для игрока
stock EventEngine:IsSceneActiveForPlayer(playerid, scene_id)
{
for (new i = 0; i < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]; i++)
{
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][i] == scene_id)
return true;
}
return false;
}

// Уничтожение всех сцен игрока
stock EventEngine:DestroyPlayerScenes(playerid, bool:keep_persistent = false)
{
printf("[EventEngine] Уничтожение сцен для игрока %d (persistent: %d)", playerid, _:keep_persistent);

for (new i = 0; i < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]; i++)
{
new scene_id = g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][i];
new scene[E_SCENE_DATA] = g_EventEngine_Scenes[scene_id];

if (keep_persistent && (scene[E_SCENE_FLAGS] & SCENE_FLAG_PERSISTENT))
continue;

EventEngine:DeactivatePlayerScene(playerid, scene_id);
i--; // Уменьшаем счетчик т.к. массив сдвинулся
}

// Восстанавливаем исходные настройки
if (g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT] == 0)
{
SetPlayerWeather(playerid, g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_WEATHER]);
ResetPlayerTime(playerid);
SetPlayerInterior(playerid, g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_INTERIOR]);
SetPlayerVirtualWorld(playerid, g_EventEngine_PlayerScenes[playerid][E_PLAYER_CURRENT_WORLD]);
}
}

// Интеграция с системой заданий - обновляем при смене задания
stock EventEngine:SetPlayerTask(playerid, task_id, bool:is_on_login = false)
{
// ... существующий код смены задания ...

// Обновляем сцены после смены задания
EventEngine:UpdatePlayerScenes(playerid, task_id);

// ... остальной код ...
}

// Обработка отключения игрока
public OnPlayerDisconnect(playerid, reason)
{
EventEngine:DestroyPlayerScenes(playerid, false);

// ... остальной код ...
return 1;
}

// Обработка выхода из зоны
public OnPlayerLeaveDynamicArea(playerid, areaid)
{
for (new i = 0; i < g_EventEngine_PlayerScenes[playerid][E_PLAYER_SCENE_COUNT]; i++)
{
new scene_id = g_EventEngine_PlayerScenes[playerid][E_PLAYER_ACTIVE_SCENES][i];
new scene[E_SCENE_DATA] = g_EventEngine_Scenes[scene_id];

if ((scene[E_SCENE_FLAGS] & SCENE_FLAG_ZONE_BASED) && scene[E_SCENE_ZONE_ID] == areaid)
{
EventEngine:DeactivatePlayerScene(playerid, scene_id);
i--;
}
}

return 1;
}

// Пример создания сцены для задания "Поиск реквизита"
public Circus_OnTaskInit(task_id)
{
if (task_id == TASK_FIND_PROPS)
{
// Создаем сцену с реквизитом в цирке
new scene_id = EventEngine:CreateScene(
EVENT_CIRCUS,
"Реквизит цирка",
TASK_FIND_PROPS,
TASK_FIND_PROPS_FINISH,
SCENE_FLAG_AUTO_DESTROY
);

// Добавляем объекты реквизита
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_OBJECT,
35.8412, 1945.6732, 9.8203, 19315, 0.0, 0.0, 0.0); // Ящик с реквизитом

EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_OBJECT,
33.1289, 1943.4512, 9.8203, 19632, 0.0, 0.0, 90.0); // Костюмы

// Добавляем NPC охраны
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_NPC,
37.2198, 1942.1289, 9.8203, 71, 180.0); // Охранник

// Добавляем атмосферный звук
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_SOUND,
35.0, 1945.0, 10.0, "circus/ambient/storage.mp3", 15.0);
}
}

// Пример сцены с транспортом для задания доставки
public Circus_OnPlayerStartTask(playerid, sub_task)
{
new task_id = EventEngine:GetPlayerTask(playerid);

if (task_id == TASK_DELIVER_PROPS)
{
// Создаем индивидуальный транспорт для доставки
new scene_id = EventEngine:CreateScene(
EVENT_CIRCUS,
"Транспорт доставки",
TASK_DELIVER_PROPS,
TASK_DELIVER_PROPS_FINISH,
SCENE_FLAG_AUTO_DESTROY
);

// Добавляем фургон для доставки
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_VEHICLE,
45.2198, 1950.1289, 10.1203, 498, 270.0); // Фургон Boxville

// Устанавливаем погоду для атмосферы
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_WEATHER,
0.0, 0.0, 0.0, 8); // Туманная погода

// Устанавливаем вечернее время
EventEngine:AddSceneEntity(scene_id, SCENE_ENTITY_TIME,
0.0, 0.0, 0.0, 20, 0); // 20:00
}
}