C#:
using Oxide.Core.Plugins;
using UnityEngine;
using System.Collections.Generic;
using Rust.Ai; // <- Agregado para BaseNpc
using Oxide.Game.Rust.Cui;
namespace Oxide.Plugins
{
[Info("MiniEventMVP", "TuNombre", "0.1")]
[Description("Prototipo MVP para evento de oleadas")]
public class MiniEventMVP : RustPlugin
{
private Dictionary<ulong, int> jugadorRonda = new Dictionary<ulong, int>();
private List<BaseEntity> muroEntities = new List<BaseEntity>();
private Dictionary<int, string> armasPorRonda = new Dictionary<int, string>
{
{ 1, "rifle.ak" },
{ 2, "smg.2" },
{ 3, "shotgun.pump" }
};
private Dictionary<ulong, List<BaseEntity>> botsActivos = new Dictionary<ulong, List<BaseEntity>>();
[ChatCommand("startminievent")]
private void CmdStartMiniEvent(BasePlayer player, string command, string[] args)
{
if (!player.IsAdmin)
{
player.ChatMessage("Solo admins pueden usar este comando por ahora.");
return;
}
if (jugadorRonda.ContainsKey(player.userID))
{
player.ChatMessage("Ya estás en el evento.");
return;
}
jugadorRonda[player.userID] = 1;
botsActivos[player.userID] = new List<BaseEntity>();
CrearCirculoMurallas(player);
IniciarRonda(player);
}
[ChatCommand("limpiarme")]
private void CmdLimpiarListaJugadoresEnRonda(BasePlayer player, string command, string[] args)
{
jugadorRonda.Remove(player.userID);
}
[ChatCommand("crearmurallas")]
private void CrearCirculoMurallas(BasePlayer player)
{
Vector3 centro = player.transform.position;
DestruirMurallas();
float radio = 15f;
int cantidad = 16;
float anguloPaso = 360f / cantidad;
for (int i = 0; i < cantidad; i++)
{
float angulo = anguloPaso * i;
float rad = angulo * Mathf.Deg2Rad;
Vector3 offset = new Vector3(Mathf.Cos(rad), 0, Mathf.Sin(rad)) * radio;
Vector3 pos = centro + offset;
Puts($"Intentando crear muralla en: {pos}");
var muro = GameManager.server.CreateEntity("assets/prefabs/building/wall.external.high.stone/wall.external.high.stone.prefab", pos);
if (muro != null)
{
Vector3 dirHaciaCentro = (centro - pos).normalized;
muro.transform.rotation = Quaternion.LookRotation(dirHaciaCentro);
muro.Spawn();
Puts($"Muralla creada en: {muro.transform.position}");
muroEntities.Add(muro);
}
else
{
Puts("Error: No se pudo crear la entidad muro.");
}
}
}
[ChatCommand("crearmurallas")]
private void CMDCrearCirculoMurallas(BasePlayer player, string command, string[] args){
CrearCirculoMurallas(player);
}
[ChatCommand("destruirmurallas")]
private void CMDDestruirMurallas(BasePlayer player, string command, string[] args){
DestruirMurallas();
}
private void spawnearBoss(BasePlayer player){
jugadorRonda[player.userID] += 1;
float offsetX = UnityEngine.Random.Range(-5f, 5f);
float offsetZ = UnityEngine.Random.Range(-5f, 5f);
Vector3 spawnPos = player.transform.position + new Vector3(offsetX, 10f, offsetZ); // 10m arriba para raycast hacia abajo
// Raycast hacia abajo para encontrar el suelo
if (Physics.Raycast(spawnPos, Vector3.down, out RaycastHit hit, 20f, LayerMask.GetMask("Terrain", "World", "Construction")))
{
spawnPos.y = hit.point.y;
}
else
{
// Si no se detecta suelo, usar la Y del jugador para no spawnear en el aire
spawnPos.y = player.transform.position.y;
}
var npc = GameManager.server.CreateEntity("assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab", spawnPos) as BaseEntity;
if (npc != null)
{
npc.Spawn();
botsActivos[player.userID].Add(npc);
var npcPlayer = npc.GetComponent<NPCPlayer>();
if (npcPlayer != null)
{
npcPlayer.SetMaxHealth(1000f);
npcPlayer.Heal(npcPlayer.MaxHealth());
}
}
timer.Once(10f, () =>
{
FinalizarEvento(player);
DestruirMurallas();
});
}
private void DestruirMurallas()
{
foreach (var muro in muroEntities)
{
if (muro != null && !muro.IsDestroyed)
{
muro.Kill();
}
}
muroEntities.Clear();
}
private void IniciarRonda(BasePlayer player)
{
int ronda = jugadorRonda[player.userID];
Puts($"Iniciando ronda {ronda} para {player.displayName}");
// Spawnea 4 bots scientist básicos cerca del jugador
for (int i = 0; i < 4; i++)
{
// Generar posición aleatoria dentro de un cuadrado de +-5 metros en X y Z respecto al jugador
float offsetX = UnityEngine.Random.Range(-5f, 5f);
float offsetZ = UnityEngine.Random.Range(-5f, 5f);
Vector3 spawnPos = player.transform.position + new Vector3(offsetX, 10f, offsetZ); // 10m arriba para raycast hacia abajo
// Raycast hacia abajo para encontrar el suelo
if (Physics.Raycast(spawnPos, Vector3.down, out RaycastHit hit, 20f, LayerMask.GetMask("Terrain", "World", "Construction")))
{
spawnPos.y = hit.point.y;
}
else
{
// Si no se detecta suelo, usar la Y del jugador para no spawnear en el aire
spawnPos.y = player.transform.position.y;
}
var npc = GameManager.server.CreateEntity("assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_oilrig.prefab", spawnPos) as BaseEntity;
if (npc != null)
{
npc.Spawn();
botsActivos[player.userID].Add(npc);
var npcPlayer = npc.GetComponent<NPCPlayer>();
if (npcPlayer != null)
{
npcPlayer.health = 100 + ronda * 50;
npcPlayer.Heal(npcPlayer.MaxHealth());
}
}
}
// Timer para limpiar bots y pasar a siguiente ronda o finalizar
MostrarContador(player, 10);
timer.Once(10f, () =>
{
LimpiarBots(player);
//CAMBIAR ACA
if (ronda < 0)
{
jugadorRonda[player.userID] += 1;
timer.Once(3f, () => IniciarRonda(player));
}else if(ronda == 1){
timer.Once(3f, () => spawnearBoss(player));
}
});
}
private void LimpiarBots(BasePlayer player)
{
if (!botsActivos.ContainsKey(player.userID)) return;
foreach (var bot in botsActivos[player.userID])
{
if (bot != null && !bot.IsDestroyed)
{
bot.Kill();
}
}
botsActivos[player.userID].Clear();
}
private void FinalizarEvento(BasePlayer player)
{
jugadorRonda.Remove(player.userID);
botsActivos.Remove(player.userID);
player.ChatMessage("¡Evento completado! Recompensa desplegada.");
Vector3 pos = player.transform.position + Vector3.up;
for (int i = 0; i < 3; i++)
{
var crate = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/bradley_crate.prefab", pos + new Vector3(0, 0, i));
if (crate != null)
{
crate.Spawn();
crate.SetFlag(BaseEntity.Flags.Locked, false);
var storage = crate.GetComponent<StorageContainer>();
if (storage != null)
{
storage.inventory.GiveItem(ItemManager.CreateByName("metal.refined", 10));
storage.inventory.GiveItem(ItemManager.CreateByName("rifle.ak", 1));
}
}
}
}
private void MostrarContador(BasePlayer player, int segundos)
{
string panelName = "ContadorUI_" + player.userID;
// Asegurarse de limpiar cualquier UI previa
CuiHelper.DestroyUi(player, panelName);
// Crear UI inicial (panel + label)
void AddContadorUI(int value)
{
var container = new CuiElementContainer();
// Panel contenedor (background)
container.Add(new CuiPanel
{
Image = { Color = "0 0 255 1" },
RectTransform = { AnchorMin = "0.45 0.9", AnchorMax = "0.55 0.95" },
CursorEnabled = false
}, "Hud", panelName);
// Label con el número
container.Add(new CuiLabel
{
Text = { Text = value.ToString(), FontSize = 22, Align = TextAnchor.MiddleCenter, Color = "1 1 1 1" },
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
}, panelName);
// Reemplazamos la UI completa
CuiHelper.DestroyUi(player, panelName);
CuiHelper.AddUi(player, container);
}
// Añadimos UI inicial
AddContadorUI(segundos);
// Contador por closure (no pasar argumentos al callback)
int ticks = 0;
timer.Repeat(1f, segundos, () =>
{
ticks++;
int tiempoRestante = segundos - ticks;
// Actualizar UI con el nuevo valor
AddContadorUI(Mathf.Max(0, tiempoRestante));
// Si llegó a 0, desactivar UI
if (tiempoRestante <= 0)
{
CuiHelper.DestroyUi(player, panelName);
}
});
}
}
}