C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Radiation Zone", "0killrest", "1.0.0")]
[Description("High-risk radiation zone with rewards for survival")]
internal class RadiationZone : RustPlugin
{
#region Configuration
private static ConfigData config;
private class ConfigData
{
public bool Enabled { get; set; } = true;
public float ZoneRadius { get; set; } = 50f;
public Vector3 ZoneCenter { get; set; } = new Vector3(0, 0, 0);
public int RadiationPerSecond { get; set; } = 15;
public int PointsPerSecond { get; set; } = 1;
public bool ShowZoneOnMap { get; set; } = true;
public string ZoneMarkerName { get; set; } = "radiation_zone";
public List<RewardItem> Rewards { get; set; }
public ConfigData()
{
Rewards = new List<RewardItem>
{
new RewardItem { ShortName = "scrap", Amount = 50, PointsCost = 100, DisplayName = "Scrap x50" },
new RewardItem { ShortName = "metal.refined", Amount = 20, PointsCost = 80, DisplayName = "Metal Fragments x20" },
new RewardItem { ShortName = "sulfur", Amount = 30, PointsCost = 90, DisplayName = "Sulfur x30" },
new RewardItem { ShortName = "cloth", Amount = 50, PointsCost = 40, DisplayName = "Cloth x50" },
new RewardItem { ShortName = "rifle.ak", Amount = 1, PointsCost = 500, DisplayName = "AK-47" }
};
}
}
public class RewardItem
{
public string ShortName { get; set; }
public int Amount { get; set; }
public int PointsCost { get; set; }
public string DisplayName { get; set; }
}
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<ConfigData>();
if (config == null)
{
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig()
{
config = new ConfigData();
PrintWarning("Default configuration created.Edit it in oxide/config/RadiationZone.json");
PrintWarning("Don't forget to set ZoneCenter coordinates for your map!");
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Data Storage
private Dictionary<ulong, PlayerZoneData> playerData;
private class PlayerZoneData
{
public int Points { get; set; } = 0;
public bool IsInZone { get; set; } = false;
public float LastTickTime { get; set; } = 0f;
}
private void LoadData()
{
playerData = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, PlayerZoneData>>("RadiationZone_Data") ?? new Dictionary<ulong, PlayerZoneData>();
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject("RadiationZone_Data", playerData);
}
#endregion
#region Hooks
private GameObject markerObject;
private Dictionary<ulong, Timer> radiationTimers = new Dictionary<ulong, Timer>();
private void Init()
{
LoadData();
permission.RegisterPermission("radiationzone.admin", this);
}
private void OnServerInitialized()
{
if (config.Enabled && config.ShowZoneOnMap)
{
CreateMapMarker();
}
}
private void Unload()
{
if (markerObject != null)
UnityEngine.Object.Destroy(markerObject);
foreach (var timer in radiationTimers.Values)
{
timer?.Destroy();
}
radiationTimers.Clear();
SaveData();
}
private void OnServerSave() => SaveData();
private void OnPlayerTick(BasePlayer player, float deltaTime)
{
if (!config.Enabled) return;
if (player == null || player.IsDead()) return;
bool isInZone = IsPlayerInZone(player);
if (!playerData.ContainsKey(player.userID))
{
playerData[player.userID] = new PlayerZoneData();
}
var data = playerData[player.userID];
if (isInZone && !data.IsInZone)
{
// Entered zone
data.IsInZone = true;
SendReply(player, $"<color=red>⚠️ You entered the RADIATION ZONE!</color> You receive {config.PointsPerSecond} points per second.Use <color=yellow>/zone rewards</color> to spend points.");
StartRadiationTimer(player);
}
else if (!isInZone && data.IsInZone)
{
// Exited zone
data.IsInZone = false;
SendReply(player, $"<color=green>You left the radiation zone.You have {data.Points} points saved!</color>");
StopRadiationTimer(player);
// Heal radiation slowly
player.metabolism.radiation_poison.value = Math.Max(0, player.metabolism.radiation_poison.value - 5);
}
// Accumulate points while in zone
if (data.IsInZone)
{
if (Time.realtimeSinceStartup - data.LastTickTime >= 1.0f)
{
data.LastTickTime = Time.realtimeSinceStartup;
// Apply radiation damage
player.metabolism.radiation_poison.value += config.RadiationPerSecond;
// Give points
data.Points += config.PointsPerSecond;
SaveData();
// Show floating text
Effect.server.Run("assets/prefabs/missions/portal/proximity_portal/effects/range_check.prefab", player.transform.position, Vector3.zero);
// Random message every 10 seconds
if (data.Points % (config.PointsPerSecond * 10) == 0)
{
SendReply(player, $"<color=yellow>🏆 Radiation survival: {data.Points} points earned!</color>");
}
}
}
}
private bool IsPlayerInZone(BasePlayer player)
{
float distance = Vector3.Distance(player.transform.position, config.ZoneCenter);
return distance <= config.ZoneRadius;
}
private void StartRadiationTimer(BasePlayer player)
{
if (radiationTimers.ContainsKey(player.userID))
{
radiationTimers[player.userID]?.Destroy();
radiationTimers.Remove(player.userID);
}
// Check every 5 seconds for lethal radiation
radiationTimers[player.userID] = timer.Repeat(5f, 0, () =>
{
if (player == null || !player.IsConnected || player.IsDead())
{
StopRadiationTimer(player);
return;
}
var data = playerData[player.userID];
if (data != null && data.IsInZone && player.metabolism.radiation_poison.value >= 400)
{
SendReply(player, $"<color=red>💀 You died from radiation poisoning! Lost 50% of your zone points.</color>");
data.Points = Math.Max(0, (int)(data.Points * 0.5f));
SaveData();
}
});
}
private void StopRadiationTimer(BasePlayer player)
{
if (radiationTimers.ContainsKey(player.userID))
{
radiationTimers[player.userID]?.Destroy();
radiationTimers.Remove(player.userID);
}
}
private void CreateMapMarker()
{
if (markerObject != null)
UnityEngine.Object.Destroy(markerObject);
markerObject = new GameObject(config.ZoneMarkerName);
var marker = markerObject.AddComponent<MapMarkerGenericRadius>();
marker.radius = config.ZoneRadius / 2f;
marker.color1 = new Color(1f, 0f, 0f, 0.7f); // Red
marker.color2 = new Color(1f, 0.5f, 0f, 0.5f); // Orange
marker.alpha = 0.8f;
marker.ServerInit();
marker.transform.position = config.ZoneCenter;
marker.SendUpdate();
Puts($"Radiation zone marker created at {config.ZoneCenter} with radius {config.ZoneRadius}");
}
#endregion
#region Commands
[ChatCommand("zone")]
private void cmdZone(BasePlayer player, string command, string[] args)
{
if (args.Length == 0)
{
SendReply(player, "<color=yellow>=== Radiation Zone ===</color>");
SendReply(player, "/zone info - Show zone info and your points");
SendReply(player, "/zone rewards - Show available rewards");
SendReply(player, "/zone buy <id> - Buy reward by ID");
return;
}
switch (args[0].ToLower())
{
case "info":
ShowInfo(player);
break;
case "rewards":
ShowRewards(player);
break;
case "buy":
if (args.Length > 1 && int.TryParse(args[1], out int id))
{
BuyReward(player, id);
}
else
{
SendReply(player, "Usage: /zone buy <reward_id>");
}
break;
default:
SendReply(player, "Unknown command.Use /zone");
break;
}
}
private void ShowInfo(BasePlayer player)
{
var data = playerData.ContainsKey(player.userID) ? playerData[player.userID] : new PlayerZoneData();
bool inZone = IsPlayerInZone(player);
SendReply(player, "<color=yellow>=== Zone Info ===</color>");
SendReply(player, $"📍 Center: {config.ZoneCenter}");
SendReply(player, $"📏 Radius: {config.ZoneRadius}m");
SendReply(player, $"☢️ Radiation/sec: {config.RadiationPerSecond}");
SendReply(player, $"⭐ Points/sec: {config.PointsPerSecond}");
SendReply(player, $"💰 Your points: {data.Points}");
SendReply(player, $"🚩 Currently in zone: {(inZone ? "<color=red>YES</color>" : "<color=green>NO</color>")}");
}
private void ShowRewards(BasePlayer player)
{
SendReply(player, "<color=yellow>=== Available Rewards ===</color>");
for (int i = 0; i < config.Rewards.Count; i++)
{
var reward = config.Rewards[i];
SendReply(player, $"<color=cyan>{i + 1}</color>.{reward.DisplayName} - <color=orange>{reward.PointsCost} points</color>");
}
}
private void BuyReward(BasePlayer player, int rewardId)
{
if (rewardId < 1 || rewardId > config.Rewards.Count)
{
SendReply(player, "Invalid reward ID!");
return;
}
var reward = config.Rewards[rewardId - 1];
var data = playerData.ContainsKey(player.userID) ? playerData[player.userID] : new PlayerZoneData();
if (data.Points < reward.PointsCost)
{
SendReply(player, $"<color=red>Not enough points! You have {data.Points}, need {reward.PointsCost}</color>");
return;
}
// Give item
ItemDefinition itemDef = ItemManager.FindItemDefinition(reward.ShortName);
if (itemDef == null)
{
PrintError($"Item '{reward.ShortName}' not found!");
SendReply(player, "Error: item not found, contact admin");
return;
}
Item item = ItemManager.Create(itemDef, reward.Amount);
if (item != null && player.inventory.GiveItem(item))
{
data.Points -= reward.PointsCost;
SaveData();
SendReply(player, $"<color=green>✅ You bought {reward.DisplayName} for {reward.PointsCost} points! Remaining: {data.Points}</color>");
// Visual effect
Effect.server.Run("assets/prefabs/locks/keylock/effects/lock.code.updated.prefab", player.transform.position, Vector3.zero);
}
else
{
SendReply(player, "Failed to give item.Inventory full?");
}
}
[ConsoleCommand("radiationzone.setcenter")]
private void cmdSetCenter(ConsoleSystem.Arg args)
{
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "radiationzone.admin"))
{
args.ReplyWith("No permission");
return;
}
if (args.Args == null || args.Args.Length < 3)
{
args.ReplyWith("Usage: radiationzone.setcenter <x> <z> (y will be auto-detected)");
return;
}
float x = Convert.ToSingle(args.Args[0]);
float z = Convert.ToSingle(args.Args[1]);
float y = TerrainMeta.HeightMap.GetHeight(new Vector3(x, 0, z));
config.ZoneCenter = new Vector3(x, y, z);
SaveConfig();
if (config.ShowZoneOnMap)
{
CreateMapMarker();
}
args.ReplyWith($"Radiation zone center set to {config.ZoneCenter} with radius {config.ZoneRadius}");
Puts($"Radiation zone center updated to {config.ZoneCenter}");
}
[ConsoleCommand("radiationzone.radius")]
private void cmdSetRadius(ConsoleSystem.Arg args)
{
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "radiationzone.admin"))
{
args.ReplyWith("No permission");
return;
}
if (args.Args == null || args.Args.Length < 1)
{
args.ReplyWith("Usage: radiationzone.radius <radius>");
return;
}
config.ZoneRadius = Convert.ToSingle(args.Args[0]);
SaveConfig();
if (config.ShowZoneOnMap)
{
CreateMapMarker();
}
args.ReplyWith($"Radiation zone radius set to {config.ZoneRadius}");
}
[ConsoleCommand("radiationzone.givepoints")]
private void cmdGivePoints(ConsoleSystem.Arg args)
{
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "radiationzone.admin"))
{
args.ReplyWith("No permission");
return;
}
if (args.Args == null || args.Args.Length < 2)
{
args.ReplyWith("Usage: radiationzone.givepoints <steamID> <amount>");
return;
}
ulong steamId = Convert.ToUInt64(args.Args[0]);
int amount = Convert.ToInt32(args.Args[1]);
if (!playerData.ContainsKey(steamId))
{
playerData[steamId] = new PlayerZoneData();
}
playerData[steamId].Points += amount;
SaveData();
args.ReplyWith($"Gave {amount} points to {steamId}");
}
#endregion
}
}