Форум Pawn.Wiki - Воплоти мечту в реальность!: Rust - SA-MP - Форум Pawn.Wiki - Воплоти мечту в реальность!

Перейти к содержимому

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

[ Survival ]
Rust - SA-MP
Оценка: -----

#1
Пользователь офлайн   pinople 

  • Прохожий
  • Вставить ник
  • Раскрыть информацию
// RUST MODE FOR SA-MP
// Main include files
#include <a_samp>
#include <a_mysql>
#include <streamer>
#include <sscanf2>
#include <foreach>
#include <zcmd>
#include <progress2>
#include <YSI\y_timers>
#include <YSI\y_iterate>

// Definitions
#define SERVER_NAME "RUST SA-MP"
#define SCRIPT_VERSION "1.0.0"

// Database connection
new MySQL:g_SQL;

// Colors
#define COLOR_RED 0xFF0000FF
#define COLOR_GREEN 0x33AA33FF
#define COLOR_BLUE 0x0000FFFF
#define COLOR_YELLOW 0xFFFF00FF
#define COLOR_ORANGE 0xFF9900FF
#define COLOR_PURPLE 0xC2A2DAFF
#define COLOR_WHITE 0xFFFFFFFF
#define COLOR_BLACK 0x000000FF
#define COLOR_GRAY 0xAFAFAFFF
#define COLOR_BROWN 0xA52A2AFF

// Dialogs
#define DIALOG_LOGIN 1
#define DIALOG_REGISTER 2
#define DIALOG_INVENTORY 3
#define DIALOG_CRAFTING 4
#define DIALOG_CRAFTING_CONFIRM 5
#define DIALOG_BUILDING 6
#define DIALOG_LOOT 7
#define DIALOG_PLAYER_MENU 8
#define DIALOG_ADMIN 9
#define DIALOG_ADMIN_SPAWN 10

// Player variables
enum pInfo
{
    pID,
    pName[MAX_PLAYER_NAME],
    pPassword[65],
    pAdmin,
    pKills,
    pDeaths,
    Float:pHealth,
    Float:pArmor,
    Float:pHunger,
    Float:pThirst,
    Float:pRadiation,
    pMaterials[5], // 0 - Wood, 1 - Stone, 2 - Metal, 3 - Cloth, 4 - Fuel
    pInventory[30],
    pInventoryAmount[30],
    Float:pLastX,
    Float:pLastY,
    Float:pLastZ,
    pInterior,
    pVirtualWorld,
    pSpawnPoint,
    pBuildingMode,
    pBuildingType,
    pBuildingRotation,
    pLootingID,
    pProgressBar,
    pHungerBar,
    pThirstBar,
    pRadiationBar,
    pHasMap,
    pLastLogin,
    pRegisterDate,
    pPlaytime,
    pSleeping
}
new PlayerInfo[MAX_PLAYERS][pInfo];

// Resources objects
#define MAX_RESOURCES 1000
enum resInfo
{
    resType, // 0 - Wood, 1 - Stone, 2 - Metal, 3 - Hemp, 4 - Food, 5 - Barrel
    resObject,
    Float:resX,
    Float:resY,
    Float:resZ,
    Float:resRX,
    Float:resRY,
    Float:resRZ,
    resAmount,
    resHealth,
    bool:resActive,
    resRespawnTime
}
new ResourceInfo[MAX_RESOURCES][resInfo];
new ResourceCount = 0;

// Buildings system
#define MAX_BUILDINGS 5000
enum buildInfo
{
    buildID,
    buildOwner,
    buildType, // 0 - Foundation, 1 - Wall, 2 - Doorway, 3 - Door, 4 - Floor, 5 - Ceiling, 6 - Stairs, 7 - Window, 8 - Chest
    buildObject,
    Float:buildX,
    Float:buildY,
    Float:buildZ,
    Float:buildRX,
    Float:buildRY,
    Float:buildRZ,
    buildHealth,
    buildMaxHealth,
    buildLockCode[10],
    buildLocked,
    buildItemID[20],
    buildItemAmount[20]
}
new BuildingInfo[MAX_BUILDINGS][buildInfo];
new BuildingCount = 0;

// Items definitions
#define ITEM_HATCHET 1
#define ITEM_PICKAXE 2
#define ITEM_HAMMER 3
#define ITEM_FOOD 4
#define ITEM_WATER 5
#define ITEM_MEDKIT 6
#define ITEM_BANDAGE 7
#define ITEM_PISTOL 8
#define ITEM_RIFLE 9
#define ITEM_SHOTGUN 10
#define ITEM_AMMO_PISTOL 11
#define ITEM_AMMO_RIFLE 12
#define ITEM_AMMO_SHOTGUN 13
#define ITEM_RADIATION_SUIT 14
#define ITEM_MAP 15
#define ITEM_SLEEPING_BAG 16
#define ITEM_FURNACE 17
#define ITEM_CAMPFIRE 18
#define ITEM_CODELOCK 19
#define ITEM_KEYLOCK 20
#define ITEM_KEY 21
#define ITEM_WOOD_DOOR 22
#define ITEM_METAL_DOOR 23
#define ITEM_METAL_FRAGMENTS 24
#define ITEM_CHARCOAL 25
#define ITEM_GUNPOWDER 26
#define ITEM_EXPLOSIVE 27
#define ITEM_C4 28
#define ITEM_SULFUR 29
#define ITEM_CRUDE_OIL 30

// Loot containers
#define MAX_LOOT_CONTAINERS 500
enum lootInfo
{
    lootType, // 0 - Barrel, 1 - Crate, 2 - Military Crate, 3 - Elite Crate, 4 - Dead Body
    lootObject,
    Float:lootX,
    Float:lootY,
    Float:lootZ,
    lootInterior,
    lootVW,
    lootItems[10],
    lootItemsAmount[10],
    bool:lootActive,
    lootRespawnTime
}
new LootInfo[MAX_LOOT_CONTAINERS][lootInfo];
new LootCount = 0;

// Radiation zones
#define MAX_RADIATION_ZONES 10
enum radInfo
{
    Float:radX,
    Float:radY,
    Float:radZ,
    Float:radRadius,
    radLevel // 1-5, intensity of radiation
}
new RadiationZones[MAX_RADIATION_ZONES][radInfo];
new RadiationZoneCount = 0;

// Sleeping players
#define MAX_SLEEPING_PLAYERS 500
enum sleepInfo
{
    sleepName[MAX_PLAYER_NAME],
    sleepUserID,
    sleepObject,
    Float:sleepX,
    Float:sleepY,
    Float:sleepZ,
    Float:sleepRot,
    sleepInterior,
    sleepVW,
    bool:sleepActive,
    sleepInventory[30],
    sleepInventoryAmount[30],
    sleepMaterials[5],
    Float:sleepHealth,
    Float:sleepArmor,
    Float:sleepHunger,
    Float:sleepThirst
}
new SleepingPlayers[MAX_SLEEPING_PLAYERS][sleepInfo];
new SleepingCount = 0;

// Forward declarations
forward OnPlayerDataCheck(playerid);
forward OnPlayerRegister(playerid);
forward OnInventoryLoad(playerid);
forward UpdateHunger(playerid);
forward UpdateThirst(playerid);
forward CheckRadiationExposure(playerid);
forward UpdateResourceHealth(resourceid, playerid, damage);
forward RespawnResource(resourceid);
forward OnBuildingsLoad();
forward OnLootLoad();
forward OnLootRespawn(lootid);
forward HealOverTime(playerid);
forward UpdateGlobalTimers();
forward CreateSleepingBag(playerid);
forward PlayerSleepSave(playerid);
forward SaveAllBuildings();
forward RandomAirDrop();
forward UpdateAllPlayersHUDInfo();

// Main code
public OnGameModeInit()
{
    print("\n--------------------------------------");
    print("Loading Rust SA-MP Gamemode...");
    print("--------------------------------------\n");
    
    // Game mode info
    SetGameModeText(SERVER_NAME);
    
    // Connect to database
    g_SQL = mysql_connect("localhost", "username", "password", "rustdb");
    if(mysql_errno() != 0) 
    {
        print("MySQL Connection Failed!");
        return 0;
    }
    print("MySQL connection successful!");
    
    // Create tables if not exists
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS players (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(24), password VARCHAR(65), admin INT, kills INT, deaths INT, health FLOAT, armor FLOAT, hunger FLOAT, thirst FLOAT, radiation FLOAT, wood INT, stone INT, metal INT, cloth INT, fuel INT, lastX FLOAT, lastY FLOAT, lastZ FLOAT, interior INT, virtualworld INT, spawnpoint INT, hasmap INT, lastlogin INT, registerdate INT, playtime INT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS inventory (player_id INT, slot INT, item_id INT, amount INT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS buildings (id INT AUTO_INCREMENT PRIMARY KEY, owner INT, type INT, x FLOAT, y FLOAT, z FLOAT, rx FLOAT, ry FLOAT, rz FLOAT, health INT, maxhealth INT, lockcode VARCHAR(10), locked INT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS building_items (building_id INT, slot INT, item_id INT, amount INT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS sleeping_players (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(24), user_id INT, x FLOAT, y FLOAT, z FLOAT, rot FLOAT, interior INT, virtualworld INT, active INT, health FLOAT, armor FLOAT, hunger FLOAT, thirst FLOAT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS sleeping_inventory (sleep_id INT, slot INT, item_id INT, amount INT)");
    mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS sleeping_materials (sleep_id INT, wood INT, stone INT, metal INT, cloth INT, fuel INT)");
    
    // Game settings
    ShowPlayerMarkers(0);
    ShowNameTags(1);
    SetNameTagDrawDistance(20.0);
    DisableInteriorEnterExits();
    EnableStuntBonusForAll(0);
    SetWeather(2);
    
    // Create radiation zones
    CreateRadiationZones();
    
    // Spawn resources
    SpawnAllResources();
    
    // Load buildings
    LoadBuildings();
    
    // Spawn loot containers
    LoadLootContainers();
    
    // Load sleeping players
    LoadSleepingPlayers();
    
    // Set global timer
    SetTimer("UpdateGlobalTimers", 1000, true);
    SetTimer("SaveAllBuildings", 300000, true); // Save buildings every 5 minutes
    SetTimer("RandomAirDrop", 3600000, true); // Air drop every hour
    
    print("\n--------------------------------------");
    print(SERVER_NAME " Gamemode Loaded Successfully!");
    print("--------------------------------------\n");
    
    return 1;
}

public OnGameModeExit()
{
    // Save all players data
    foreach(new i : Player)
    {
        SavePlayerData(i);
        
        if(IsValidProgressBar(PlayerInfo[i][pProgressBar]))
            DestroyProgressBar(PlayerInfo[i][pProgressBar]);
            
        if(IsValidProgressBar(PlayerInfo[i][pHungerBar]))
            DestroyProgressBar(PlayerInfo[i][pHungerBar]);
            
        if(IsValidProgressBar(PlayerInfo[i][pThirstBar]))
            DestroyProgressBar(PlayerInfo[i][pThirstBar]);
            
        if(IsValidProgressBar(PlayerInfo[i][pRadiationBar]))
            DestroyProgressBar(PlayerInfo[i][pRadiationBar]);
    }
    
    // Save all buildings
    SaveAllBuildings();
    
    // Close MySQL connection
    mysql_close(g_SQL);
    
    print("\n--------------------------------------");
    print(SERVER_NAME " Gamemode Shutdown Complete!");
    print("--------------------------------------\n");
    
    return 1;
}

public OnPlayerConnect(playerid)
{
    // Reset player data
    ResetPlayerData(playerid);
    
    // Create HUD
    PlayerInfo[playerid][pProgressBar] = CreateProgressBar(548.0, 35.0, 56.0, 9.0, COLOR_GREEN, 100.0);
    PlayerInfo[playerid][pHungerBar] = CreateProgressBar(548.0, 46.0, 56.0, 9.0, COLOR_ORANGE, 100.0);
    PlayerInfo[playerid][pThirstBar] = CreateProgressBar(548.0, 57.0, 56.0, 9.0, COLOR_BLUE, 100.0);
    PlayerInfo[playerid][pRadiationBar] = CreateProgressBar(548.0, 68.0, 56.0, 9.0, COLOR_YELLOW, 100.0);
    
    ShowProgressBarForPlayer(playerid, PlayerInfo[playerid][pProgressBar]);
    ShowProgressBarForPlayer(playerid, PlayerInfo[playerid][pHungerBar]);
    ShowProgressBarForPlayer(playerid, PlayerInfo[playerid][pThirstBar]);
    ShowProgressBarForPlayer(playerid, PlayerInfo[playerid][pRadiationBar]);
    
    // Check if player exists in database
    new query[128], name[MAX_PLAYER_NAME];
    GetPlayerName(playerid, name, sizeof(name));
    mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM players WHERE name = '%e'", name);
    mysql_tquery(g_SQL, query, "OnPlayerDataCheck", "i", playerid);
    
    // Send welcome message
    SendClientMessage(playerid, COLOR_GREEN, "Welcome to "SERVER_NAME"!");
    SendClientMessage(playerid, COLOR_WHITE, "This is a survival game based on Rust. Gather resources, build a base, and survive!");
    
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    // Save player data
    SavePlayerData(playerid);
    
    // Create sleeping player if not in safe zone
    if(!IsPlayerInSafeZone(playerid) && PlayerInfo[playerid][pHealth] > 0.0)
    {
        PlayerSleepSave(playerid);
    }
    
    // Destroy progress bars
    if(IsValidProgressBar(PlayerInfo[playerid][pProgressBar]))
        DestroyProgressBar(PlayerInfo[playerid][pProgressBar]);
        
    if(IsValidProgressBar(PlayerInfo[playerid][pHungerBar]))
        DestroyProgressBar(PlayerInfo[playerid][pHungerBar]);
        
    if(IsValidProgressBar(PlayerInfo[playerid][pThirstBar]))
        DestroyProgressBar(PlayerInfo[playerid][pThirstBar]);
        
    if(IsValidProgressBar(PlayerInfo[playerid][pRadiationBar]))
        DestroyProgressBar(PlayerInfo[playerid][pRadiationBar]);
    
    return 1;
}

public OnPlayerSpawn(playerid)
{
    // Set player's health and basic stats
    SetPlayerHealth(playerid, PlayerInfo[playerid][pHealth]);
    SetPlayerArmour(playerid, PlayerInfo[playerid][pArmor]);
    
    // Set default skin
    SetPlayerSkin(playerid, 73 + random(5)); // Random survivor skin
    
    // Give basic tools if new player
    if(PlayerInfo[playerid][pSpawnPoint] == 0)
    {
        GivePlayerBasicKit(playerid);
        
        // Random spawn location on beach
        new rand = random(10);
        new Float:spawnX, Float:spawnY, Float:spawnZ;
        
        switch(rand)
        {
            case 0: { spawnX = -1867.0; spawnY = -88.0; spawnZ = 15.0; } // Beach locations
            case 1: { spawnX = -1650.0; spawnY = 150.0; spawnZ = 15.0; }
            case 2: { spawnX = -1250.0; spawnY = 320.0; spawnZ = 15.0; }
            case 3: { spawnX = -850.0; spawnY = 450.0; spawnZ = 15.0; }
            case 4: { spawnX = -450.0; spawnY = 520.0; spawnZ = 15.0; }
            case 5: { spawnX = 100.0; spawnY = 550.0; spawnZ = 15.0; }
            case 6: { spawnX = 450.0; spawnY = 450.0; spawnZ = 15.0; }
            case 7: { spawnX = 750.0; spawnY = 300.0; spawnZ = 15.0; }
            case 8: { spawnX = 1050.0; spawnY = 120.0; spawnZ = 15.0; }
            case 9: { spawnX = 1450.0; spawnY = -80.0; spawnZ = 15.0; }
        }
        
        SetPlayerPos(playerid, spawnX, spawnY, spawnZ);
    }
    else if(PlayerInfo[playerid][pSpawnPoint] == 1) // Sleeping bag spawn
    {
        // Look for player's sleeping bag
        for(new i = 0; i < BuildingCount; i++)
        {
            if(BuildingInfo[i][buildType] == 16 && BuildingInfo[i][buildOwner] == PlayerInfo[playerid][pID])
            {
                SetPlayerPos(playerid, BuildingInfo[i][buildX], BuildingInfo[i][buildY], BuildingInfo[i][buildZ] + 1.0);
                SetPlayerFacingAngle(playerid, BuildingInfo[i][buildRZ]);
                SetPlayerInterior(playerid, 0);
                SetPlayerVirtualWorld(playerid, 0);
                break;
            }
        }
    }
    else // Last position
    {
        SetPlayerPos(playerid, PlayerInfo[playerid][pLastX], PlayerInfo[playerid][pLastY], PlayerInfo[playerid][pLastZ]);
        SetPlayerInterior(playerid, PlayerInfo[playerid][pInterior]);
        SetPlayerVirtualWorld(playerid, PlayerInfo[playerid][pVirtualWorld]);
    }
    
    // Start survival timers
    UpdatePlayerHUDInfo(playerid);
    
    // Display welcome back message
    new string[128];
    format(string, sizeof(string), "Welcome back! Health: %.1f | Hunger: %.1f | Thirst: %.1f", 
        PlayerInfo[playerid][pHealth], 
        PlayerInfo[playerid][pHunger], 
        PlayerInfo[playerid][pThirst]);
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
    // Update stats
    PlayerInfo[playerid][pDeaths]++;
    
    if(killerid != INVALID_PLAYER_ID)
    {
        PlayerInfo[killerid][pKills]++;
        
        // Give XP and possibly loot to killer
        new string[128];
        format(string, sizeof(string), "You killed %s and earned 50 XP!", GetPlayerNameEx(playerid));
        SendClientMessage(killerid, COLOR_GREEN, string);
        
        format(string, sizeof(string), "You were killed by %s!", GetPlayerNameEx(killerid));
        SendClientMessage(playerid, COLOR_RED, string);
    }
    else
    {
        SendClientMessage(playerid, COLOR_RED, "You died!");
    }
    
    // Create death loot container
    CreateDeathLoot(playerid);
    
    // Reset player's data
    ResetPlayerInventory(playerid);
    PlayerInfo[playerid][pHealth] = 100.0;
    PlayerInfo[playerid][pArmor] = 0.0;
    PlayerInfo[playerid][pHunger] = 100.0;
    PlayerInfo[playerid][pThirst] = 100.0;
    PlayerInfo[playerid][pRadiation] = 0.0;
    
    for(new i = 0; i < 5; i++)
    {
        PlayerInfo[playerid][pMaterials][i] = 0;
    }
    
    // Reset player's spawn point to random (no sleeping bag when dead)
    PlayerInfo[playerid][pSpawnPoint] = 0;
    
    // Save data
    SavePlayerData(playerid);
    
    return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    return 0; // All commands are handled by ZCMD
}

public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
    // Left mouse button (KEY_FIRE) for gathering resources and hitting
    if(newkeys & KEY_FIRE) 
    {
        // If player is in building mode, cancel action
        if(PlayerInfo[playerid][pBuildingMode])
            return 1;
            
        // Check if player is gathering resources
        if(GetPlayerWeapon(playerid) == 0 || GetPlayerWeapon(playerid) == 1)
            GatherResource(playerid);
            
        // Check if player is hitting a building (raiding)
        if(GetPlayerWeapon(playerid) >= 1 && GetPlayerWeapon(playerid) <= 46)
            HitBuilding(playerid);
    }
    
    // Right mouse button (KEY_SECONDARY_ATTACK) for building placement/interaction
    if(newkeys & KEY_SECONDARY_ATTACK) 
    {
        // Building placement mode
        if(PlayerInfo[playerid][pBuildingMode])
        {
            PlaceBuilding(playerid);
            return 1;
        }
        
        // Check for building interaction
        InteractWithBuilding(playerid);
    }
    
    // Y key for inventory
    if(newkeys & KEY_YES) 
    {
        ShowPlayerInventory(playerid);
    }
    
    // N key for crafting menu
    if(newkeys & KEY_NO) 
    {
        ShowCraftingMenu(playerid);
    }
    
    // H key for help menu
    if(newkeys & KEY_WALK) 
    {
        ShowHelpMenu(playerid);
    }
    
    return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    switch(dialogid)
    {
        case DIALOG_LOGIN:
        {
            if(!response) return Kick(playerid);
            
            new query[128], hash[65], name[MAX_PLAYER_NAME];
            GetPlayerName(playerid, name, sizeof(name));
            
            SHA256_PassHash(inputtext, "", hash, sizeof(hash));
            
            mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM players WHERE name = '%e' AND password = '%e'", name, hash);
            mysql_tquery(g_SQL, query, "OnPlayerLogin", "i", playerid);
        }
        
        case DIALOG_REGISTER:
        {
            if(!response) return Kick(playerid);
            
            if(strlen(inputtext) < 6)
            {
                SendClientMessage(playerid, COLOR_RED, "Password must be at least 6 characters long!");
                ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Register", "Please create a password for your account (min 6 chars):", "Register", "Quit");
                return 1;
            }
            
            new query[128], hash[65], name[MAX_PLAYER_NAME];
            GetPlayerName(playerid, name, sizeof(name));
            
            SHA256_PassHash(inputtext, "", hash, sizeof(hash));
            
            mysql_format(g_SQL, query, sizeof(query), "INSERT INTO players (name, password, admin, kills, deaths, health, armor, hunger, thirst, radiation, wood, stone, metal, cloth, fuel, lastX, lastY, lastZ, interior, virtualworld, spawnpoint, hasmap, lastlogin, registerdate, playtime) VALUES ('%e', '%e', 0, 0, 0, 100.0, 0.0, 100.0, 100.0, 0.0, 0, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0, 0, 0, 0, %d, %d, 0)", name, hash, gettime(), gettime());
            mysql_tquery(g_SQL, query, "OnPlayerRegister", "i", playerid);
        }
        
        case DIALOG_INVENTORY:
        {
            if(!response) return 1;
            
            // Handle inventory item usage
            new item = PlayerInfo[playerid][pInventory][listitem];
            new amount = PlayerInfo[playerid][pInventoryAmount][listitem];
            
            if(item == 0 || amount == 0) return SendClientMessage(playerid, COLOR_RED, "This slot is empty!");
            
            // Handle item usage based on item ID
            switch(item)
            {
                case ITEM_FOOD:
                {
                    // Add hunger
                    PlayerInfo[playerid][pHunger] += 25.0;
                    if(PlayerInfo[playerid][pHunger] > 100.0) PlayerInfo[playerid][pHunger] = 100.0;
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You ate food. Hunger +25");
                    UpdatePlayerHUDInfo(playerid);
                }
                
                case ITEM_WATER:
                {
                    // Add thirst
                    PlayerInfo[playerid][pThirst] += 30.0;
                    if(PlayerInfo[playerid][pThirst] > 100.0) PlayerInfo[playerid][pThirst] = 100.0;
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You drank water. Thirst +30");
                    UpdatePlayerHUDInfo(playerid);
                }
                
                case ITEM_MEDKIT:
                {
                    // Add health
                    new Float:health;
                    GetPlayerHealth(playerid, health);
                    health += 50.0;
                    if(health > 100.0) health = 100.0;
                    SetPlayerHealth(playerid, health);
                    PlayerInfo[playerid][pHealth] = health;
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You used a medkit. Health +50");
                    UpdatePlayerHUDInfo(playerid);
                }
                
                case ITEM_BANDAGE:
                {
                    // Add health
                    new Float:health;
                    GetPlayerHealth(playerid, health);
                    health += 15.0;
                    if(health > 100.0) health = 100.0;
                    SetPlayerHealth(playerid, health);
                    PlayerInfo[playerid][pHealth] = health;
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You used a bandage. Health +15");
                    UpdatePlayerHUDInfo(playerid);
                }
                
                case ITEM_RADIATION_SUIT:
                {
                    // Equip radiation suit (provides protection against radiation)
                    PlayerInfo[playerid][pInventory][listitem] = 0;
                    PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    
                    // Change player's skin to radiation suit
                    SetPlayerSkin(playerid, 285); // Hazmat suit skin
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You equipped a radiation suit. You're protected from radiation.");
                }
                
                case ITEM_MAP:
                {
                    // Activate map
                    PlayerInfo[playerid][pHasMap] = 1;
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You now have a map. Press M to view it.");
                }
                
                case ITEM_SLEEPING_BAG:
                {
                    // Place sleeping bag
                    PlayerInfo[playerid][pBuildingMode] = 1;
                    PlayerInfo[playerid][pBuildingType] = 16; // Sleeping bag
                    PlayerInfo[playerid][pInventory][listitem] = 0;
                    PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    
                    SendClientMessage(playerid, COLOR_GREEN, "Right-click to place your sleeping bag. This will be your spawn point.");
                }
                
                // Equip weapons
                case ITEM_PISTOL:
                {
                    GivePlayerWeapon(playerid, 22, PlayerInfo[playerid][pInventoryAmount][listitem]);
                    PlayerInfo[playerid][pInventory][listitem] = 0;
                    PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You equipped a pistol.");
                }
                
                case ITEM_RIFLE:
                {
                    GivePlayerWeapon(playerid, 30, PlayerInfo[playerid][pInventoryAmount][listitem]);
                    PlayerInfo[playerid][pInventory][listitem] = 0;
                    PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You equipped a rifle.");
                }
                
                case ITEM_SHOTGUN:
                {
                    GivePlayerWeapon(playerid, 25, PlayerInfo[playerid][pInventoryAmount][listitem]);
                    PlayerInfo[playerid][pInventory][listitem] = 0;
                    PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    
                    SendClientMessage(playerid, COLOR_GREEN, "You equipped a shotgun.");
                }
                
                // Building items
                case ITEM_HAMMER:
                {
                    ShowBuildingMenu(playerid);
                }
                
                case ITEM_FURNACE:
                {
                    PlayerInfo[playerid][pBuildingMode] = 1;
                    PlayerInfo[playerid][pBuildingType] = 17; // Furnace
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "Right-click to place your furnace.");
                }
                
                case ITEM_CAMPFIRE:
                {
                    PlayerInfo[playerid][pBuildingMode] = 1;
                    PlayerInfo[playerid][pBuildingType] = 18; // Campfire
                    
                    // Remove item
                    PlayerInfo[playerid][pInventoryAmount][listitem]--;
                    if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                    {
                        PlayerInfo[playerid][pInventory][listitem] = 0;
                        PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                    }
                    
                    SendClientMessage(playerid, COLOR_GREEN, "Right-click to place your campfire.");
                }
                
                case ITEM_C4:
                {
                    // Using C4 on a nearby door
                    new bool:found = false;
                    new Float:x, Float:y, Float:z;
                    GetPlayerPos(playerid, x, y, z);
                    
                    for(new i = 0; i < BuildingCount; i++)
                    {
                        if((BuildingInfo[i][buildType] == 3 || BuildingInfo[i][buildType] == 23) && // Door types
                           GetDistanceBetweenPoints3D(x, y, z, BuildingInfo[i][buildX], BuildingInfo[i][buildY], BuildingInfo[i][buildZ]) < 3.0)
                        {
                            // Plant C4
                            found = true;
                            
                            // Remove item
                            PlayerInfo[playerid][pInventoryAmount][listitem]--;
                            if(PlayerInfo[playerid][pInventoryAmount][listitem] <= 0)
                            {
                                PlayerInfo[playerid][pInventory][listitem] = 0;
                                PlayerInfo[playerid][pInventoryAmount][listitem] = 0;
                            }
                            
                            // Create explosion after 10 seconds
                            SetTimerEx("ExplodeC4", 10000, false, "i", i);
                            
                            SendClientMessage(playerid, COLOR_RED, "C4 planted! It will explode in 10 seconds.");
                            
                            // Create beeping sound
                            for(new j = 0; j < 10; j++)
                            {
                                SetTimerEx("PlayBeepSound", j * 1000, false, "i", playerid);
                            }
                            
                            break;
                        }
                    }
                    
                    if(!found)
                    {
                        SendClientMessage(playerid, COLOR_RED, "No door nearby to place C4 on!");
                    }
                }
                
                default:
                {
                    new string[128];
                    format(string, sizeof(string), "Selected Item: %d, Amount: %d", item, amount);
                    SendClientMessage(playerid, COLOR_WHITE, string);
                }
            }
            
            // Show inventory again
            ShowPlayerInventory(playerid);
        }
        
        case DIALOG_CRAFTING:
        {
            if(!response) return 1;
            
            // Selected item to craft
            new itemType;
            
            switch(listitem)
            {
                case 0: itemType = ITEM_HATCHET; // Hatchet
                case 1: itemType = ITEM_PICKAXE; // Pickaxe
                case 2: itemType = ITEM_HAMMER; // Hammer
                case 3: itemType = ITEM_BANDAGE; // Bandage
                case 4: itemType = ITEM_MEDKIT; // Medkit
                case 5: itemType = ITEM_SLEEPING_BAG; // Sleeping Bag
                case 6: itemType = ITEM_FURNACE; // Furnace
                case 7: itemType = ITEM_CAMPFIRE; // Campfire
                case 8: itemType = ITEM_WOOD_DOOR; // Wooden Door
                case 9: itemType = ITEM_METAL_DOOR; // Metal Door
                case 10: itemType = ITEM_CODELOCK; // Code Lock
                case 11: itemType = ITEM_PISTOL; // Pistol
                case 12: itemType = ITEM_SHOTGUN; // Shotgun
                case 13: itemType = ITEM_RIFLE; // Rifle
                case 14: itemType = ITEM_AMMO_PISTOL; // Pistol Ammo
                case 15: itemType = ITEM_AMMO_SHOTGUN; // Shotgun Ammo
                case 16: itemType = ITEM_AMMO_RIFLE; // Rifle Ammo
                case 17: itemType = ITEM_GUNPOWDER; // Gunpowder
                case 18: itemType = ITEM_EXPLOSIVE; // Explosive
                case 19: itemType = ITEM_C4; // C4
            }
            
            // Get crafting requirements
            new wood, stone, metal, cloth, other, otherItem;
            GetCraftingRequirements(itemType, wood, stone, metal, cloth, other, otherItem);
            
            // Check if player has required resources
            new string[512];
            format(string, sizeof(string), "Crafting Requirements:\n\n");
            
            if(wood > 0)
                format(string, sizeof(string), "%sWood: %d/%d\n", string, PlayerInfo[playerid][pMaterials][0], wood);
                
            if(stone > 0)
                format(string, sizeof(string), "%sStone: %d/%d\n", string, PlayerInfo[playerid][pMaterials][1], stone);
                
            if(metal > 0)
                format(string, sizeof(string), "%sMetal: %d/%d\n", string, PlayerInfo[playerid][pMaterials][2], metal);
                
            if(cloth > 0)
                format(string, sizeof(string), "%sCloth: %d/%d\n", string, PlayerInfo[playerid][pMaterials][3], cloth);
            
            if(other > 0)
            {
                new otherName[32];
                GetItemName(otherItem, otherName);
                
                new count = 0;
                for(new i = 0; i < 30; i++)
                {
                    if(PlayerInfo[playerid][pInventory][i] == otherItem)
                        count += PlayerInfo[playerid][pInventoryAmount][i];
                }
                
                format(string, sizeof(string), "%s%s: %d/%d\n", string, otherName, count, other);
            }
            
            // Check if player can craft the item
            if(PlayerInfo[playerid][pMaterials][0] >= wood && 
               PlayerInfo[playerid][pMaterials][1] >= stone && 
               PlayerInfo[playerid][pMaterials][2] >= metal && 
               PlayerInfo[playerid][pMaterials][3] >= cloth)
            {
                // Check for special items if needed
                new bool:hasOtherItem = true;
                
                if(other > 0)
                {
                    new count = 0;
                    for(new i = 0; i < 30; i++)
                    {
                        if(PlayerInfo[playerid][pInventory][i] == otherItem)
                            count += PlayerInfo[playerid][pInventoryAmount][i];
                    }
                    
                    if(count < other)
                        hasOtherItem = false;
                }
                
                if(hasOtherItem)
                {
                    // Calculate crafting time
                    new craftTime = GetCraftingTime(itemType);
                    
                    // Set player's crafting information
                    SetPVarInt(playerid, "CraftingItem", itemType);
                    SetPVarInt(playerid, "CraftingWood", wood);
                    SetPVarInt(playerid, "CraftingStone", stone);
                    SetPVarInt(playerid, "CraftingMetal", metal);
                    SetPVarInt(playerid, "CraftingCloth", cloth);
                    SetPVarInt(playerid, "CraftingOtherItem", otherItem);
                    SetPVarInt(playerid, "CraftingOtherAmount", other);
                    
                    format(string, sizeof(string), "%s\nYou have all required materials. Craft this item?", string);
                    ShowPlayerDialog(playerid, DIALOG_CRAFTING_CONFIRM, DIALOG_STYLE_MSGBOX, "Confirm Crafting", string, "Craft", "Cancel");
                }
                else
                {
                    format(string, sizeof(string), "%s\nYou don't have enough materials to craft this item!", string);
                    ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Crafting Failed", string, "Back", "");
                }
            }
            else
            {
                format(string, sizeof(string), "%s\nYou don't have enough materials to craft this item!", string);
                ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Crafting Failed", string, "Back", "");
            }
        }
        
        case DIALOG_CRAFTING_CONFIRM:
        {
            if(!response) return ShowCraftingMenu(playerid);
            
            // Get crafting data
            new itemType = GetPVarInt(playerid, "CraftingItem");
            new wood = GetPVarInt(playerid, "CraftingWood");
            new stone = GetPVarInt(playerid, "CraftingStone");
            new metal = GetPVarInt(playerid, "CraftingMetal");
            new cloth = GetPVarInt(playerid, "CraftingCloth");
            new otherItem = GetPVarInt(playerid, "CraftingOtherItem");
            new otherAmount = GetPVarInt(playerid, "CraftingOtherAmount");
            
            // Deduct resources
            PlayerInfo[playerid][pMaterials][0] -= wood;
            PlayerInfo[playerid][pMaterials][1] -= stone;
            PlayerInfo[playerid][pMaterials][2] -= metal;
            PlayerInfo[playerid][pMaterials][3] -= cloth;
            
            // Deduct special items if needed
            if(otherAmount > 0)
            {
                new remaining = otherAmount;
                
                for(new i = 0; i < 30 && remaining > 0; i++)
                {
                    if(PlayerInfo[playerid][pInventory][i] == otherItem)
                    {
                        if(PlayerInfo[playerid][pInventoryAmount][i] <= remaining)
                        {
                            remaining -= PlayerInfo[playerid][pInventoryAmount][i];
                            PlayerInfo[playerid][pInventory][i] = 0;
                            PlayerInfo[playerid][pInventoryAmount][i] = 0;
                        }
                        else
                        {
                            PlayerInfo[playerid][pInventoryAmount][i] -= remaining;
                            remaining = 0;
                        }
                    }
                }
            }
            
            // Calculate crafting time
            new craftTime = GetCraftingTime(itemType);
            
            // Show crafting progress
            TogglePlayerControllable(playerid, 0);
            GameTextForPlayer(playerid, "~y~Crafting...", craftTime * 1000, 3);
            ApplyAnimation(playerid, "BD_FIRE", "wash_up", 4.1, 1, 0, 0, 1, craftTime * 1000, 1);
            
            // Start crafting timer
            SetTimerEx("FinishCrafting", craftTime * 1000, false, "ii", playerid, itemType);
            
            // Display crafting message
            new itemName[32];
            GetItemName(itemType, itemName);
            
            new string[128];
            format(string, sizeof(string), "Crafting %s... Please wait %d seconds.", itemName, craftTime);
            SendClientMessage(playerid, COLOR_GREEN, string);
        }
        
        case DIALOG_BUILDING:
        {
            if(!response) return 1;
            
            // Selected building component
            new buildType;
            
            switch(listitem)
            {
                case 0: buildType = 0; // Foundation
                case 1: buildType = 1; // Wall
                case 2: buildType = 2; // Doorway
                case 3: buildType = 4; // Floor
                case 4: buildType = 5; // Ceiling
                case 5: buildType = 6; // Stairs
                case 6: buildType = 7; // Window
                case 7: buildType = 8; // Storage Box
            }
            
            // Check if player has required resources
            new wood, stone, metal;
            GetBuildingRequirements(buildType, wood, stone, metal);
            
            if(PlayerInfo[playerid][pMaterials][0] >= wood && 
               PlayerInfo[playerid][pMaterials][1] >= stone && 
               PlayerInfo[playerid][pMaterials][2] >= metal)
            {
                // Enable building mode
                PlayerInfo[playerid][pBuildingMode] = 1;
                PlayerInfo[playerid][pBuildingType] = buildType;
                PlayerInfo[playerid][pBuildingRotation] = 0;
                
                // Deduct resources
                PlayerInfo[playerid][pMaterials][0] -= wood;
                PlayerInfo[playerid][pMaterials][1] -= stone;
                PlayerInfo[playerid][pMaterials][2] -= metal;
                
                SendClientMessage(playerid, COLOR_GREEN, "Building mode enabled. Right-click to place, Q/E to rotate. Right-click again to cancel.");
            }
            else
            {
                new string[256];
                format(string, sizeof(string), "Building Requirements:\nWood: %d/%d\nStone: %d/%d\nMetal: %d/%d\n\nYou don't have enough materials!", 
                    PlayerInfo[playerid][pMaterials][0], wood,
                    PlayerInfo[playerid][pMaterials][1], stone,
                    PlayerInfo[playerid][pMaterials][2], metal);
                    
                ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Building Failed", string, "Back", "");
            }
        }
        
        case DIALOG_LOOT:
        {
            if(!response) return 1;
            
            // Player is taking an item from a loot container
            new lootid = PlayerInfo[playerid][pLootingID];
            
            if(lootid == -1 || !LootInfo[lootid][lootActive])
            {
                SendClientMessage(playerid, COLOR_RED, "This container is no longer available!");
                return 1;
            }
            
            new itemID = LootInfo[lootid][lootItems][listitem];
            new amount = LootInfo[lootid][lootItemsAmount][listitem];
            
            if(itemID == 0 || amount == 0)
            {
                SendClientMessage(playerid, COLOR_RED, "This slot is empty!");
                return ShowLootContainer(playerid, lootid);
            }
            
            // Add item to player's inventory
            new slot = FindFreeInventorySlot(playerid, itemID);
            
            if(slot == -1)
            {
                SendClientMessage(playerid, COLOR_RED, "Your inventory is full!");
                return ShowLootContainer(playerid, lootid);
            }
            
            // Transfer item
            if(PlayerInfo[playerid][pInventory][slot] == 0)
            {
                PlayerInfo[playerid][pInventory][slot] = itemID;
                PlayerInfo[playerid][pInventoryAmount][slot] = amount;
            }
            else
            {
                PlayerInfo[playerid][pInventoryAmount][slot] += amount;
            }
            
            // Remove from loot container
            LootInfo[lootid][lootItems][listitem] = 0;
            LootInfo[lootid][lootItemsAmount][listitem] = 0;
            
            // Get item name
            new itemName[32];
            GetItemName(itemID, itemName);
            
            // Send message
            new string[128];
            format(string, sizeof(string), "You took %s x%d from the container.", itemName, amount);
            SendClientMessage(playerid, COLOR_GREEN, string);
            
            // Show loot container again
            ShowLootContainer(playerid, lootid);
        }
        
        case DIALOG_PLAYER_MENU:
        {
            if(!response) return 1;
            
            switch(listitem)
            {
                case 0: // Stats
                {
                    new string[512];
                    format(string, sizeof(string), "Player Statistics\n\n");
                    format(string, sizeof(string), "%sName: %s\n", string, GetPlayerNameEx(playerid));
                    format(string, sizeof(string), "%sKills: %d\n", string, PlayerInfo[playerid][pKills]);
                    format(string, sizeof(string), "%sDeaths: %d\n", string, PlayerInfo[playerid][pDeaths]);
                    format(string, sizeof(string), "%sK/D Ratio: %.2f\n", string, PlayerInfo[playerid][pDeaths] > 0 ? float(PlayerInfo[playerid][pKills]) / float(PlayerInfo[playerid][pDeaths]) : float(PlayerInfo[playerid][pKills]));
                    format(string, sizeof(string), "%sPlay Time: %d hours\n", string, PlayerInfo[playerid][pPlaytime] / 3600);
                    
                    ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Player Statistics", string, "Close", "");
                }
                
                case 1: // Inventory
                {
                    ShowPlayerInventory(playerid);
                }
                
                case 2: // Crafting
                {
                    ShowCraftingMenu(playerid);
                }
                
                case 3: // Building
                {
                    ShowBuildingMenu(playerid);
                }
                
                case 4: // Help
                {
                    ShowHelpMenu(playerid);
                }
                
                case 5: // Admin Panel (if admin)
                {
                    if(PlayerInfo[playerid][pAdmin] >= 1)
                    {
                        ShowAdminMenu(playerid);
                    }
                    else
                    {
                        SendClientMessage(playerid, COLOR_RED, "You are not an administrator!");
                    }
                }
            }
        }
        
        case DIALOG_ADMIN:
        {
            if(!response) return 1;
            
            if(PlayerInfo[playerid][pAdmin] < 1)
                return SendClientMessage(playerid, COLOR_RED, "You are not an administrator!");
                
            switch(listitem)
            {
                case 0: // Teleport to coordinates
                {
                    ShowPlayerDialog(playerid, DIALOG_ADMIN + 1, DIALOG_STYLE_INPUT, "Admin Teleport", "Enter coordinates (X Y Z):", "Teleport", "Cancel");
                }
                
                case 1: // Spawn item
                {
                    ShowPlayerDialog(playerid, DIALOG_ADMIN + 2, DIALOG_STYLE_INPUT, "Spawn Item", "Enter Item ID and Amount (ID Amount):", "Spawn", "Cancel");
                }
                
                case 2: // Spawn resource
                {
                    ShowPlayerDialog(playerid, DIALOG_ADMIN_SPAWN, DIALOG_STYLE_LIST, "Spawn Resource", "Wood Tree\nStone Node\nMetal Node\nHemp Plant\nBarrel\nCrate\nMilitary Crate", "Spawn", "Cancel");
                }
                
                case 3: // Kill player
                {
                    new string[512], count = 0;
                    
                    foreach(new i : Player)
                    {
                        format(string, sizeof(string), "%s%s (ID: %d)\n", string, GetPlayerNameEx(i), i);
                        count++;
                    }
                    
                    if(count == 0)
                    {
                        SendClientMessage(playerid, COLOR_RED, "No players online to kill!");
                        return ShowAdminMenu(playerid);
                    }
                    
                    ShowPlayerDialog(playerid, DIALOG_ADMIN + 3, DIALOG_STYLE_LIST, "Kill Player", string, "Kill", "Cancel");
                }
                
                case 4: // Reset server
                {
                    if(PlayerInfo[playerid][pAdmin] < 3) // Require level 3 admin
                    {
                        SendClientMessage(playerid, COLOR_RED, "You need admin level 3 to use this command!");
                        return ShowAdminMenu(playerid);
                    }
                    
                    ShowPlayerDialog(playerid, DIALOG_ADMIN + 4, DIALOG_STYLE_MSGBOX, "Reset Server", "Are you sure you want to reset the server?\nThis will kick all players and restart the script.", "Reset", "Cancel");
                }
                
                case 5: // Set admin level
                {
                    if(PlayerInfo[playerid][pAdmin] < 3) // Require level 3 admin
                    {
                        SendClientMessage(playerid, COLOR_RED, "You need admin level 3 to use this command!");
                        return ShowAdminMenu(playerid);
                    }
                    
                    new string[512], count = 0;
                    
                    foreach(new i : Player)
                    {
                        format(string, sizeof(string), "%s%s (ID: %d, Admin Level: %d)\n", string, GetPlayerNameEx(i), i, PlayerInfo[i][pAdmin]);
                        count++;
                    }
                    
                    if(count == 0)
                    {
                        SendClientMessage(playerid, COLOR_RED, "No players online to set admin level!");
                        return ShowAdminMenu(playerid);
                    }
                    
                    ShowPlayerDialog(playerid, DIALOG_ADMIN + 5, DIALOG_STYLE_LIST, "Set Admin Level", string, "Select", "Cancel");
                }
            }
        }
    }
    
    return 1;
}

public OnPlayerUpdate(playerid)
{
    // Update player's data
    new Float:health;
    GetPlayerHealth(playerid, health);
    PlayerInfo[playerid][pHealth] = health;
    
    new Float:armour;
    GetPlayerArmour(playerid, armour);
    PlayerInfo[playerid][pArmor] = armour;
    
    // Check radiation exposure
    CheckRadiationExposure(playerid);
    
    // Update HUD occasionally (not every frame)
    if(GetTickCount() % 5000 < 50) // Update roughly every 5 seconds
    {
        UpdatePlayerHUDInfo(playerid);
    }
    
    return 1;
}

public OnPlayerPickUpPickup(playerid, pickupid)
{
    return 1;
}

// Timer functions
forward FinishCrafting(playerid, itemType);
public FinishCrafting(playerid, itemType)
{
    if(!IsPlayerConnected(playerid)) return 0;
    
    // Enable player controls
    TogglePlayerControllable(playerid, 1);
    ClearAnimations(playerid);
    
    // Add crafted item to inventory
    new slot = FindFreeInventorySlot(playerid, itemType);
    
    if(slot == -1)
    {
        SendClientMessage(playerid, COLOR_RED, "Inventory full! Crafted item was dropped.");
        
        // Create a loot container with the item at player's position
        new Float:x, Float:y, Float:z;
        GetPlayerPos(playerid, x, y, z);
        
        new lootid = FindFreeLootContainer();
        if(lootid != -1)
        {
            LootInfo[lootid][lootType] = 4; // Dropped item
            LootInfo[lootid][lootX] = x;
            LootInfo[lootid][lootY] = y;
            LootInfo[lootid][lootZ] = z;
            LootInfo[lootid][lootInterior] = GetPlayerInterior(playerid);
            LootInfo[lootid][lootVW] = GetPlayerVirtualWorld(playerid);
            LootInfo[lootid][lootItems][0] = itemType;
            LootInfo[lootid][lootItemsAmount][0] = 1;
            LootInfo[lootid][lootActive] = true;
            LootInfo[lootid][lootRespawnTime] = 300; // 5 minutes
            
            // Create object
            LootInfo[lootid][lootObject] = CreateDynamicObject(2969, x, y, z - 0.5, 0.0, 0.0, 0.0, GetPlayerVirtualWorld(playerid), GetPlayerInterior(playerid));
        }
    }
    else
    {
        if(PlayerInfo[playerid][pInventory][slot] == 0)
        {
            PlayerInfo[playerid][pInventory][slot] = itemType;
            PlayerInfo[playerid][pInventoryAmount][slot] = 1;
        }
        else
        {
            PlayerInfo[playerid][pInventoryAmount][slot]++;
        }
        
        // Get item name
        new itemName[32];
        GetItemName(itemType, itemName);
        
        // Display success message
        new string[128];
        format(string, sizeof(string), "You crafted a %s!", itemName);
        SendClientMessage(playerid, COLOR_GREEN, string);
    }
    
    return 1;
}

forward ExplodeC4(buildingid);
public ExplodeC4(buildingid)
{
    if(buildingid < 0 || buildingid >= BuildingCount) return 0;
    if(!IsValidDynamicObject(BuildingInfo[buildingid][buildObject])) return 0;
    
    // Create explosion effect
    CreateExplosion(BuildingInfo[buildingid][buildX], BuildingInfo[buildingid][buildY], BuildingInfo[buildingid][buildZ], 7, 5.0);
    
    // Damage the door/wall severely or destroy it
    BuildingInfo[buildingid][buildHealth] -= 500; // Huge damage
    
    if(BuildingInfo[buildingid][buildHealth] <= 0)
    {
        // Destroy the building object
        DestroyDynamicObject(BuildingInfo[buildingid][buildObject]);
        BuildingInfo[buildingid][buildObject] = INVALID_OBJECT_ID;
        
        // Remove from database
        new query[128];
        mysql_format(g_SQL, query, sizeof(query), "DELETE FROM buildings WHERE id = %d", BuildingInfo[buildingid][buildID]);
        mysql_tquery(g_SQL, query);
        
        // Also remove any items stored in it
        mysql_format(g_SQL, query, sizeof(query), "DELETE FROM building_items WHERE building_id = %d", BuildingInfo[buildingid][buildID]);
        mysql_tquery(g_SQL, query);
        
        // Notify nearby players
        foreach(new i : Player)
        {
            if(IsPlayerInRangeOfPoint(i, 50.0, BuildingInfo[buildingid][buildX], BuildingInfo[buildingid][buildY], BuildingInfo[buildingid][buildZ]))
            {
                SendClientMessage(i, COLOR_RED, "A building was destroyed by an explosion!");
            }
        }
    }
    else
    {
        // Notify nearby players
        foreach(new i : Player)
        {
            if(IsPlayerInRangeOfPoint(i, 50.0, BuildingInfo[buildingid][buildX], BuildingInfo[buildingid][buildY], BuildingInfo[buildingid][buildZ]))
            {
                SendClientMessage(i, COLOR_RED, "A building was damaged by an explosion!");
            }
        }
    }
    
    return 1;
}

forward PlayBeepSound(playerid);
public PlayBeepSound(playerid)
{
    if(!IsPlayerConnected(playerid)) return 0;
    
    PlayerPlaySound(playerid, 1139, 0.0, 0.0, 0.0); // Beep sound
    
    return 1;
}

forward UpdateGlobalTimers();
public UpdateGlobalTimers()
{
    // This function runs every second
    
    // Update all players' hunger and thirst
    foreach(new i : Player)
    {
        // Decrease hunger and thirst over time
        PlayerInfo[i][pHunger] -= 0.03; // About 1 per minute
        PlayerInfo[i][pThirst] -= 0.05; // About 1.5 per minute
        
        // Handle hunger and thirst damage
        if(PlayerInfo[i][pHunger] <= 0.0)
        {
            PlayerInfo[i][pHunger] = 0.0;
            
            // Damage player from starvation
            new Float:health;
            GetPlayerHealth(i, health);
            health -= 1.0;
            
            if(health <= 0.0)
            {
                SetPlayerHealth(i, 0.0);
            }
            else
            {
                SetPlayerHealth(i, health);
                PlayerInfo[i][pHealth] = health;
            }
            
            // Send warning message every 15 seconds
            if(gettime() % 15 == 0)
            {
                SendClientMessage(i, COLOR_RED, "You are starving! Find food!");
            }
        }
        
        if(PlayerInfo[i][pThirst] <= 0.0)
        {
            PlayerInfo[i][pThirst] = 0.0;
            
            // Damage player from dehydration
            new Float:health;
            GetPlayerHealth(i, health);
            health -= 1.5;
            
            if(health <= 0.0)
            {
                SetPlayerHealth(i, 0.0);
            }
            else
            {
                SetPlayerHealth(i, health);
                PlayerInfo[i][pHealth] = health;
            }
            
            // Send warning message every 15 seconds
            if(gettime() % 15 == 0)
            {
                SendClientMessage(i, COLOR_RED, "You are dehydrated! Find water!");
            }
        }
        
        // Update HUD every 10 seconds
        if(gettime() % 10 == 0)
        {
            UpdatePlayerHUDInfo(i);
        }
        
        // Increment playtime
        PlayerInfo[i][pPlaytime]++;
    }
    
    // Update loot container respawns
    for(new i = 0; i < LootCount; i++)
    {
        if(!LootInfo[i][lootActive] && LootInfo[i][lootRespawnTime] > 0)
        {
            LootInfo[i][lootRespawnTime]--;
            
            if(LootInfo[i][lootRespawnTime] <= 0)
            {
                RespawnLootContainer(i);
            }
        }
    }
    
    // Every 5 minutes (300 seconds), save all players' data
    if(gettime() % 300 == 0)
    {
        foreach(new i : Player)
        {
            SavePlayerData(i);
        }
        
        print("Auto-saved all players' data");
    }
    
    return 1;
}

forward SaveAllBuildings();
public SaveAllBuildings()
{
    new query[256];
    
    for(new i = 0; i < BuildingCount; i++)
    {
        if(IsValidDynamicObject(BuildingInfo[i][buildObject]))
        {
            // Update building in database
            mysql_format(g_SQL, query, sizeof(query), 
                "UPDATE buildings SET health = %d WHERE id = %d",
                BuildingInfo[i][buildHealth],
                BuildingInfo[i][buildID]
            );
            mysql_tquery(g_SQL, query);
        }
    }
    
    print("Auto-saved all buildings");
    
    return 1;
}

forward RandomAirDrop();
public RandomAirDrop()
{
    // Check if enough players are online
    new playerCount = 0;
    foreach(new i : Player)
    {
        playerCount++;
    }
    
    if(playerCount < 3) return 0; // Need at least 3 players for air drop
    
    // Generate random position
    new Float:dropX = -3000.0 + float(random(6000));
    new Float:dropY = -3000.0 + float(random(6000));
    new Float:dropZ = 0.0;
    
    // Create airdrop container
    new lootid = FindFreeLootContainer();
    if(lootid == -1) return 0;
    
    LootInfo[lootid][lootType] = 3; // Elite Crate
    LootInfo[lootid][lootX] = dropX;
    LootInfo[lootid][lootY] = dropY;
    LootInfo[lootid][lootZ] = dropZ;
    LootInfo[lootid][lootInterior] = 0;
    LootInfo[lootid][lootVW] = 0;
    LootInfo[lootid][lootActive] = true;
    LootInfo[lootid][lootRespawnTime] = 0; // Won't respawn automatically
    
    // Fill with high-tier loot
    for(new i = 0; i < 10; i++)
    {
        LootInfo[lootid][lootItems][i] = 0;
        LootInfo[lootid][lootItemsAmount][i] = 0;
    }
    
    // Add random high-tier items
    new itemCount = 3 + random(4); // 3-6 items
    
    for(new i = 0; i < itemCount; i++)
    {
        new slot = i;
        new itemType = GetRandomHighTierItem();
        new amount = 1;
        
        // Adjust amount for some items
        switch(itemType)
        {
            case ITEM_AMMO_PISTOL, ITEM_AMMO_RIFLE, ITEM_AMMO_SHOTGUN:
                amount = 10 + random(20);
            case ITEM_METAL_FRAGMENTS, ITEM_GUNPOWDER:
                amount = 50 + random(50);
        }
        
        LootInfo[lootid][lootItems][slot] = itemType;
        LootInfo[lootid][lootItemsAmount][slot] = amount;
    }
    
    // Create visual object for the airdrop
    LootInfo[lootid][lootObject] = CreateDynamicObject(2977, dropX, dropY, dropZ, 0.0, 0.0, 0.0, 0, 0);
    
    // Notify all players
    new string[128];
    format(string, sizeof(string), "An air drop has been deployed! Look for the supply crate!");
    SendClientMessageToAll(COLOR_ORANGE, string);
    
    // Create a checkpoint for the airdrop
    foreach(new i : Player)
    {
        if(PlayerInfo[i][pHasMap])
        {
            SetPlayerCheckpoint(i, dropX, dropY, dropZ, 5.0);
            SendClientMessage(i, COLOR_ORANGE, "Air drop location has been marked on your map!");
        }
    }
    
    return 1;
}

forward UpdateAllPlayersHUDInfo();
public UpdateAllPlayersHUDInfo()
{
    foreach(new i : Player)
    {
        UpdatePlayerHUDInfo(i);
    }
    
    return 1;
}

// Custom commands
CMD:inventory(playerid, params[])
{
    ShowPlayerInventory(playerid);
    return 1;
}

CMD:craft(playerid, params[])
{
    ShowCraftingMenu(playerid);
    return 1;
}

CMD:build(playerid, params[])
{
    ShowBuildingMenu(playerid);
    return 1;
}

CMD:drop(playerid, params[])
{
    new slot, amount;
    
    if(sscanf(params, "ii", slot, amount))
    {
        SendClientMessage(playerid, COLOR_WHITE, "USAGE: /drop [slot] [amount]");
        return 1;
    }
    
    if(slot < 1 || slot > 30)
    {
        SendClientMessage(playerid, COLOR_RED, "Invalid slot number (1-30)!");
        return 1;
    }
    
    slot--; // Convert to 0-based index
    
    if(PlayerInfo[playerid][pInventory][slot] == 0)
    {
        SendClientMessage(playerid, COLOR_RED, "This slot is empty!");
        return 1;
    }
    
    if(amount <= 0 || amount > PlayerInfo[playerid][pInventoryAmount][slot])
    {
        SendClientMessage(playerid, COLOR_RED, "Invalid amount!");
        return 1;
    }
    
    // Get item info
    new itemType = PlayerInfo[playerid][pInventory][slot];
    new itemName[32];
    GetItemName(itemType, itemName);
    
    // Drop the item
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    new lootid = FindFreeLootContainer();
    if(lootid != -1)
    {
        LootInfo[lootid][lootType] = 4; // Dropped item
        LootInfo[lootid][lootX] = x;
        LootInfo[lootid][lootY] = y;
        LootInfo[lootid][lootZ] = z;
        LootInfo[lootid][lootInterior] = GetPlayerInterior(playerid);
        LootInfo[lootid][lootVW] = GetPlayerVirtualWorld(playerid);
        LootInfo[lootid][lootItems][0] = itemType;
        LootInfo[lootid][lootItemsAmount][0] = amount;
        LootInfo[lootid][lootActive] = true;
        LootInfo[lootid][lootRespawnTime] = 300; // 5 minutes
        
        // Create object
        LootInfo[lootid][lootObject] = CreateDynamicObject(2969, x, y, z - 0.5, 0.0, 0.0, 0.0, GetPlayerVirtualWorld(playerid), GetPlayerInterior(playerid));
        
        // Remove from player's inventory
        PlayerInfo[playerid][pInventoryAmount][slot] -= amount;
        if(PlayerInfo[playerid][pInventoryAmount][slot] <= 0)
        {
            PlayerInfo[playerid][pInventory][slot] = 0;
            PlayerInfo[playerid][pInventoryAmount][slot] = 0;
        }
        
        // Send message
        new string[128];
        format(string, sizeof(string), "You dropped %s x%d on the ground.", itemName, amount);
        SendClientMessage(playerid, COLOR_GREEN, string);
    }
    else
    {
        SendClientMessage(playerid, COLOR_RED, "Failed to drop item. Try again later.");
    }
    
    return 1;
}

CMD:menu(playerid, params[])
{
    ShowPlayerMenu(playerid);
    return 1;
}

CMD:help(playerid, params[])
{
    ShowHelpMenu(playerid);
    return 1;
}

CMD:stats(playerid, params[])
{
    new string[512];
    format(string, sizeof(string), "Player Statistics\n\n");
    format(string, sizeof(string), "%sName: %s\n", string, GetPlayerNameEx(playerid));
    format(string, sizeof(string), "%sKills: %d\n", string, PlayerInfo[playerid][pKills]);
    format(string, sizeof(string), "%sDeaths: %d\n", string, PlayerInfo[playerid][pDeaths]);
    format(string, sizeof(string), "%sK/D Ratio: %.2f\n", string, PlayerInfo[playerid][pDeaths] > 0 ? float(PlayerInfo[playerid][pKills]) / float(PlayerInfo[playerid][pDeaths]) : float(PlayerInfo[playerid][pKills]));
    format(string, sizeof(string), "%sHealth: %.1f\n", string, PlayerInfo[playerid][pHealth]);
    format(string, sizeof(string), "%sHunger: %.1f\n", string, PlayerInfo[playerid][pHunger]);
    format(string, sizeof(string), "%sThirst: %.1f\n", string, PlayerInfo[playerid][pThirst]);
    format(string, sizeof(string), "%sRadiation: %.1f\n", string, PlayerInfo[playerid][pRadiation]);
    format(string, sizeof(string), "%sPlay Time: %d hours %d minutes\n", string, PlayerInfo[playerid][pPlaytime] / 3600, (PlayerInfo[playerid][pPlaytime] % 3600) / 60);
    
    ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Player Statistics", string, "Close", "");
    
    return 1;
}

CMD:resources(playerid, params[])
{
    new string[256];
    format(string, sizeof(string), "Resources:\n\n");
    format(string, sizeof(string), "%sWood: %d\n", string, PlayerInfo[playerid][pMaterials][0]);
    format(string, sizeof(string), "%sStone: %d\n", string, PlayerInfo[playerid][pMaterials][1]);
    format(string, sizeof(string), "%sMetal: %d\n", string, PlayerInfo[playerid][pMaterials][2]);
    format(string, sizeof(string), "%sCloth: %d\n", string, PlayerInfo[playerid][pMaterials][3]);
    format(string, sizeof(string), "%sFuel: %d\n", string, PlayerInfo[playerid][pMaterials][4]);
    
    ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Resources", string, "Close", "");
    
    return 1;
}

CMD:suicide(playerid, params[])
{
    SendClientMessage(playerid, COLOR_RED, "You committed suicide.");
    SetPlayerHealth(playerid, 0.0);
    return 1;
}

// Admin commands
CMD:admin(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] >= 1)
    {
        ShowAdminMenu(playerid);
    }
    else
    {
        SendClientMessage(playerid, COLOR_RED, "You are not an administrator!");
    }
    
    return 1;
}

CMD:aduty(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 1)
        return SendClientMessage(playerid, COLOR_RED, "You are not an administrator!");
        
    new string[128];
    
    if(GetPVarInt(playerid, "AdminDuty") == 0)
    {
        SetPVarInt(playerid, "AdminDuty", 1);
        SetPlayerColor(playerid, 0xFF0000FF); // Red color for admins
        format(string, sizeof(string), "* Administrator %s is now on duty.", GetPlayerNameEx(playerid));
        SendClientMessageToAll(COLOR_RED, string);
    }
    else
    {
        SetPVarInt(playerid, "AdminDuty", 0);
        SetPlayerColor(playerid, 0xFFFFFFFF); // White color for normal players
        format(string, sizeof(string), "* Administrator %s is now off duty.", GetPlayerNameEx(playerid));
        SendClientMessageToAll(COLOR_RED, string);
    }
    
    return 1;
}

CMD:goto(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 1)
        return SendClientMessage(playerid, COLOR_RED, "You are not an administrator!");
        
    new targetid;
    
    if(sscanf(params, "u", targetid))
        return SendClientMessage(playerid, COLOR_WHITE, "USAGE: /goto [playerid/name]");
        
    if(!IsPlayerConnected(targetid))
        return SendClientMessage(playerid, COLOR_RED, "Player not connected!");
        
    new Float:x, Float:y, Float:z;
    GetPlayerPos(targetid, x, y, z);
    
    SetPlayerPos(playerid, x, y + 2.0, z);
    SetPlayerInterior(playerid, GetPlayerInterior(targetid));
    SetPlayerVirtualWorld(playerid, GetPlayerVirtualWorld(targetid));
    
    new string[128];
    format(string, sizeof(string), "You teleported to %s.", GetPlayerNameEx(targetid));
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    return 1;
}

CMD:gethere(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 2)
        return SendClientMessage(playerid, COLOR_RED, "You are not a level 2+ administrator!");
        
    new targetid;
    
    if(sscanf(params, "u", targetid))
        return SendClientMessage(playerid, COLOR_WHITE, "USAGE: /gethere [playerid/name]");
        
    if(!IsPlayerConnected(targetid))
        return SendClientMessage(playerid, COLOR_RED, "Player not connected!");
        
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    SetPlayerPos(targetid, x, y + 2.0, z);
    SetPlayerInterior(targetid, GetPlayerInterior(playerid));
    SetPlayerVirtualWorld(targetid, GetPlayerVirtualWorld(playerid));
    
    new string[128];
    format(string, sizeof(string), "You teleported %s to your position.", GetPlayerNameEx(targetid));
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    format(string, sizeof(string), "Administrator %s teleported you.", GetPlayerNameEx(playerid));
    SendClientMessage(targetid, COLOR_GREEN, string);
    
    return 1;
}

CMD:giveitem(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 2)
        return SendClientMessage(playerid, COLOR_RED, "You are not a level 2+ administrator!");
        
    new targetid, itemid, amount;
    
    if(sscanf(params, "uii", targetid, itemid, amount))
        return SendClientMessage(playerid, COLOR_WHITE, "USAGE: /giveitem [playerid/name] [itemid] [amount]");
        
    if(!IsPlayerConnected(targetid))
        return SendClientMessage(playerid, COLOR_RED, "Player not connected!");
        
    if(itemid <= 0 || itemid > 30)
        return SendClientMessage(playerid, COLOR_RED, "Invalid item ID!");
        
    if(amount <= 0 || amount > 1000)
        return SendClientMessage(playerid, COLOR_RED, "Invalid amount (1-1000)!");
        
    // Add item to player's inventory
    new slot = FindFreeInventorySlot(targetid, itemid);
    
    if(slot == -1)
    {
        SendClientMessage(playerid, COLOR_RED, "Player's inventory is full!");
        return 1;
    }
    
    if(PlayerInfo[targetid][pInventory][slot] == 0)
    {
        PlayerInfo[targetid][pInventory][slot] = itemid;
        PlayerInfo[targetid][pInventoryAmount][slot] = amount;
    }
    else
    {
        PlayerInfo[targetid][pInventoryAmount][slot] += amount;
    }
    
    // Get item name
    new itemName[32];
    GetItemName(itemid, itemName);
    
    // Send messages
    new string[128];
    format(string, sizeof(string), "You gave %s %d x %s.", GetPlayerNameEx(targetid), amount, itemName);
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    format(string, sizeof(string), "Administrator %s gave you %d x %s.", GetPlayerNameEx(playerid), amount, itemName);
    SendClientMessage(targetid, COLOR_GREEN, string);
    
    return 1;
}

CMD:giveresource(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 2)
        return SendClientMessage(playerid, COLOR_RED, "You are not a level 2+ administrator!");
        
    new targetid, resourceid, amount;
    
    if(sscanf(params, "uii", targetid, resourceid, amount))
    {
        SendClientMessage(playerid, COLOR_WHITE, "USAGE: /giveresource [playerid/name] [resourceid] [amount]");
        SendClientMessage(playerid, COLOR_WHITE, "Resource IDs: 0=Wood, 1=Stone, 2=Metal, 3=Cloth, 4=Fuel");
        return 1;
    }
        
    if(!IsPlayerConnected(targetid))
        return SendClientMessage(playerid, COLOR_RED, "Player not connected!");
        
    if(resourceid < 0 || resourceid > 4)
        return SendClientMessage(playerid, COLOR_RED, "Invalid resource ID (0-4)!");
        
    if(amount <= 0 || amount > 10000)
        return SendClientMessage(playerid, COLOR_RED, "Invalid amount (1-10000)!");
        
    // Add resource to player
    PlayerInfo[targetid][pMaterials][resourceid] += amount;
    
    // Get resource name
    new resourceName[10];
    switch(resourceid)
    {
        case 0: resourceName = "Wood";
        case 1: resourceName = "Stone";
        case 2: resourceName = "Metal";
        case 3: resourceName = "Cloth";
        case 4: resourceName = "Fuel";
    }
    
    // Send messages
    new string[128];
    format(string, sizeof(string), "You gave %s %d x %s.", GetPlayerNameEx(targetid), amount, resourceName);
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    format(string, sizeof(string), "Administrator %s gave you %d x %s.", GetPlayerNameEx(playerid), amount, resourceName);
    SendClientMessage(targetid, COLOR_GREEN, string);
    
    return 1;
}

CMD:spawn(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 3)
        return SendClientMessage(playerid, COLOR_RED, "You are not a level 3+ administrator!");
        
    new type, Float:x, Float:y, Float:z;
    
    if(sscanf(params, "i", type))
    {
        SendClientMessage(playerid, COLOR_WHITE, "USAGE: /spawn [type]");
        SendClientMessage(playerid, COLOR_WHITE, "Types: 0=Wood, 1=Stone, 2=Metal, 3=Hemp, 4=Barrel, 5=Crate, 6=Military Crate");
        return 1;
    }
    
    if(type < 0 || type > 6)
        return SendClientMessage(playerid, COLOR_RED, "Invalid type (0-6)!");
        
    GetPlayerPos(playerid, x, y, z);
    
    if(type <= 3) // Resources
    {
        new resourceid = CreateResourceAtPos(type, x, y, z);
        
        if(resourceid != -1)
        {
            new string[128];
            
            switch(type)
            {
                case 0: format(string, sizeof(string), "You spawned a wood resource node (ID: %d).", resourceid);
                case 1: format(string, sizeof(string), "You spawned a stone resource node (ID: %d).", resourceid);
                case 2: format(string, sizeof(string), "You spawned a metal resource node (ID: %d).", resourceid);
                case 3: format(string, sizeof(string), "You spawned a hemp plant (ID: %d).", resourceid);
            }
            
            SendClientMessage(playerid, COLOR_GREEN, string);
        }
        else
        {
            SendClientMessage(playerid, COLOR_RED, "Failed to spawn resource. Maximum resources reached.");
        }
    }
    else // Loot containers
    {
        new lootid = CreateLootContainerAtPos(type - 4, x, y, z);
        
        if(lootid != -1)
        {
            new string[128];
            
            switch(type)
            {
                case 4: format(string, sizeof(string), "You spawned a barrel (ID: %d).", lootid);
                case 5: format(string, sizeof(string), "You spawned a crate (ID: %d).", lootid);
                case 6: format(string, sizeof(string), "You spawned a military crate (ID: %d).", lootid);
            }
            
            SendClientMessage(playerid, COLOR_GREEN, string);
        }
        else
        {
            SendClientMessage(playerid, COLOR_RED, "Failed to spawn loot container. Maximum containers reached.");
        }
    }
    
    return 1;
}

CMD:restart(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 3)
        return SendClientMessage(playerid, COLOR_RED, "You are not a level 3+ administrator!");
        
    // Save all players' data
    foreach(new i : Player)
    {
        SavePlayerData(i);
    }
    
    // Save all buildings
    SaveAllBuildings();
    
    // Announce restart
    SendClientMessageToAll(COLOR_RED, "SERVER RESTART: The server is being restarted by an administrator!");
    SendClientMessageToAll(COLOR_RED, "Please reconnect in a few moments.");
    
    // Kick all players
    foreach(new i : Player)
    {
        Kick(i);
    }
    
    // Restart the gamemode
    GameModeExit();
    
    return 1;
}

// Custom functions
ResetPlayerData(playerid)
{
    PlayerInfo[playerid][pID] = 0;
    GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
    PlayerInfo[playerid][pPassword][0] = '\0';
    PlayerInfo[playerid][pAdmin] = 0;
    PlayerInfo[playerid][pKills] = 0;
    PlayerInfo[playerid][pDeaths] = 0;
    PlayerInfo[playerid][pHealth] = 100.0;
    PlayerInfo[playerid][pArmor] = 0.0;
    PlayerInfo[playerid][pHunger] = 100.0;
    PlayerInfo[playerid][pThirst] = 100.0;
    PlayerInfo[playerid][pRadiation] = 0.0;
    
    for(new i = 0; i < 5; i++)
    {
        PlayerInfo[playerid][pMaterials][i] = 0;
    }
    
    for(new i = 0; i < 30; i++)
    {
        PlayerInfo[playerid][pInventory][i] = 0;
        PlayerInfo[playerid][pInventoryAmount][i] = 0;
    }
    
    PlayerInfo[playerid][pLastX] = 0.0;
    PlayerInfo[playerid][pLastY] = 0.0;
    PlayerInfo[playerid][pLastZ] = 0.0;
    PlayerInfo[playerid][pInterior] = 0;
    PlayerInfo[playerid][pVirtualWorld] = 0;
    PlayerInfo[playerid][pSpawnPoint] = 0;
    PlayerInfo[playerid][pBuildingMode] = 0;
    PlayerInfo[playerid][pBuildingType] = 0;
    PlayerInfo[playerid][pBuildingRotation] = 0;
    PlayerInfo[playerid][pLootingID] = -1;
    PlayerInfo[playerid][pHasMap] = 0;
    PlayerInfo[playerid][pLastLogin] = 0;
    PlayerInfo[playerid][pRegisterDate] = 0;
    PlayerInfo[playerid][pPlaytime] = 0;
    PlayerInfo[playerid][pSleeping] = 0;
    
    return 1;
}

ResetPlayerInventory(playerid)
{
    for(new i = 0; i < 30; i++)
    {
        PlayerInfo[playerid][pInventory][i] = 0;
        PlayerInfo[playerid][pInventoryAmount][i] = 0;
    }
    
    for(new i = 0; i < 5; i++)
    {
        PlayerInfo[playerid][pMaterials][i] = 0;
    }
    
    return 1;
}

SavePlayerData(playerid)
{
    if(PlayerInfo[playerid][pID] == 0) return 0;
    
    new query[512];
    new Float:health;
    GetPlayerHealth(playerid, health);
    PlayerInfo[playerid][pHealth] = health;
    
    new Float:armour;
    GetPlayerArmour(playerid, armour);
    PlayerInfo[playerid][pArmor] = armour;
    
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    PlayerInfo[playerid][pLastX] = x;
    PlayerInfo[playerid][pLastY] = y;
    PlayerInfo[playerid][pLastZ] = z;
    
    PlayerInfo[playerid][pInterior] = GetPlayerInterior(playerid);
    PlayerInfo[playerid][pVirtualWorld] = GetPlayerVirtualWorld(playerid);
    
    mysql_format(g_SQL, query, sizeof(query), 
        "UPDATE players SET health = %.1f, armor = %.1f, hunger = %.1f, thirst = %.1f, radiation = %.1f, wood = %d, stone = %d, metal = %d, cloth = %d, fuel = %d, lastX = %.1f, lastY = %.1f, lastZ = %.1f, interior = %d, virtualworld = %d, spawnpoint = %d, hasmap = %d, kills = %d, deaths = %d, lastlogin = %d, playtime = %d WHERE id = %d",
        PlayerInfo[playerid][pHealth],
        PlayerInfo[playerid][pArmor],
        PlayerInfo[playerid][pHunger],
        PlayerInfo[playerid][pThirst],
        PlayerInfo[playerid][pRadiation],
        PlayerInfo[playerid][pMaterials][0],
        PlayerInfo[playerid][pMaterials][1],
        PlayerInfo[playerid][pMaterials][2],
        PlayerInfo[playerid][pMaterials][3],
        PlayerInfo[playerid][pMaterials][4],
        PlayerInfo[playerid][pLastX],
        PlayerInfo[playerid][pLastY],
        PlayerInfo[playerid][pLastZ],
        PlayerInfo[playerid][pInterior],
        PlayerInfo[playerid][pVirtualWorld],
        PlayerInfo[playerid][pSpawnPoint],
        PlayerInfo[playerid][pHasMap],
        PlayerInfo[playerid][pKills],
        PlayerInfo[playerid][pDeaths],
        gettime(),
        PlayerInfo[playerid][pPlaytime],
        PlayerInfo[playerid][pID]
    );
    mysql_tquery(g_SQL, query);
    
    // Save inventory
    mysql_format(g_SQL, query, sizeof(query), "DELETE FROM inventory WHERE player_id = %d", PlayerInfo[playerid][pID]);
    mysql_tquery(g_SQL, query);
    
    for(new i = 0; i < 30; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] > 0)
        {
            mysql_format(g_SQL, query, sizeof(query), 
                "INSERT INTO inventory (player_id, slot, item_id, amount) VALUES (%d, %d, %d, %d)",
                PlayerInfo[playerid][pID],
                i,
                PlayerInfo[playerid][pInventory][i],
                PlayerInfo[playerid][pInventoryAmount][i]
            );
            mysql_tquery(g_SQL, query);
        }
    }
    
    return 1;
}

forward OnPlayerLogin(playerid);
public OnPlayerLogin(playerid)
{
    new rows;
    cache_get_row_count(rows);
    
    if(rows)
    {
        // Login successful
        PlayerInfo[playerid][pID] = cache_get_field_content_int(0, "id");
        PlayerInfo[playerid][pAdmin] = cache_get_field_content_int(0, "admin");
        PlayerInfo[playerid][pKills] = cache_get_field_content_int(0, "kills");
        PlayerInfo[playerid][pDeaths] = cache_get_field_content_int(0, "deaths");
        PlayerInfo[playerid][pHealth] = cache_get_field_content_float(0, "health");
        PlayerInfo[playerid][pArmor] = cache_get_field_content_float(0, "armor");
        PlayerInfo[playerid][pHunger] = cache_get_field_content_float(0, "hunger");
        PlayerInfo[playerid][pThirst] = cache_get_field_content_float(0, "thirst");
        PlayerInfo[playerid][pRadiation] = cache_get_field_content_float(0, "radiation");
        PlayerInfo[playerid][pMaterials][0] = cache_get_field_content_int(0, "wood");
        PlayerInfo[playerid][pMaterials][1] = cache_get_field_content_int(0, "stone");
        PlayerInfo[playerid][pMaterials][2] = cache_get_field_content_int(0, "metal");
        PlayerInfo[playerid][pMaterials][3] = cache_get_field_content_int(0, "cloth");
        PlayerInfo[playerid][pMaterials][4] = cache_get_field_content_int(0, "fuel");
        PlayerInfo[playerid][pLastX] = cache_get_field_content_float(0, "lastX");
        PlayerInfo[playerid][pLastY] = cache_get_field_content_float(0, "lastY");
        PlayerInfo[playerid][pLastZ] = cache_get_field_content_float(0, "lastZ");
        PlayerInfo[playerid][pInterior] = cache_get_field_content_int(0, "interior");
        PlayerInfo[playerid][pVirtualWorld] = cache_get_field_content_int(0, "virtualworld");
        PlayerInfo[playerid][pSpawnPoint] = cache_get_field_content_int(0, "spawnpoint");
        PlayerInfo[playerid][pHasMap] = cache_get_field_content_int(0, "hasmap");
        PlayerInfo[playerid][pLastLogin] = cache_get_field_content_int(0, "lastlogin");
        PlayerInfo[playerid][pRegisterDate] = cache_get_field_content_int(0, "registerdate");
        PlayerInfo[playerid][pPlaytime] = cache_get_field_content_int(0, "playtime");
        
        // Load inventory
        new query[128];
        mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM inventory WHERE player_id = %d", PlayerInfo[playerid][pID]);
        mysql_tquery(g_SQL, query, "OnInventoryLoad", "i", playerid);
        
        // Remove sleeping player if exists
        for(new i = 0; i < SleepingCount; i++)
        {
            if(SleepingPlayers[i][sleepUserID] == PlayerInfo[playerid][pID] && SleepingPlayers[i][sleepActive])
            {
                SleepingPlayers[i][sleepActive] = false;
                if(IsValidDynamicObject(SleepingPlayers[i][sleepObject]))
                {
                    DestroyDynamicObject(SleepingPlayers[i][sleepObject]);
                }
                
                // Remove from database
                mysql_format(g_SQL, query, sizeof(query), "DELETE FROM sleeping_players WHERE user_id = %d", PlayerInfo[playerid][pID]);
                mysql_tquery(g_SQL, query);
                
                break;
            }
        }
        
        // Send welcome message
        new string[128];
        format(string, sizeof(string), "Welcome back, %s! Last login: %s", 
            PlayerInfo[playerid][pName], 
            PlayerInfo[playerid][pLastLogin] > 0 ? FormatTimestamp(PlayerInfo[playerid][pLastLogin]) : "Never");
        SendClientMessage(playerid, COLOR_GREEN, string);
        
        // Set player's spawn info and spawn them
        SetSpawnInfo(playerid, 0, 73, PlayerInfo[playerid][pLastX], PlayerInfo[playerid][pLastY], PlayerInfo[playerid][pLastZ], 0.0, 0, 0, 0, 0, 0, 0);
        SpawnPlayer(playerid);
    }
    else
    {
        // Login failed
        SendClientMessage(playerid, COLOR_RED, "Login failed! Invalid password.");
        
        new attempts = GetPVarInt(playerid, "LoginAttempts") + 1;
        SetPVarInt(playerid, "LoginAttempts", attempts);
        
        if(attempts >= 3)
        {
            SendClientMessage(playerid, COLOR_RED, "Too many failed login attempts. You have been kicked!");
            Kick(playerid);
        }
        else
        {
            ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "Wrong password! Please enter your password:", "Login", "Quit");
        }
    }
    
    return 1;
}

public OnPlayerRegister(playerid)
{
    PlayerInfo[playerid][pID] = cache_insert_id();
    
    // Set initial stats
    PlayerInfo[playerid][pHealth] = 100.0;
    PlayerInfo[playerid][pArmor] = 0.0;
    PlayerInfo[playerid][pHunger] = 100.0;
    PlayerInfo[playerid][pThirst] = 100.0;
    PlayerInfo[playerid][pRadiation] = 0.0;
    PlayerInfo[playerid][pSpawnPoint] = 0;
    PlayerInfo[playerid][pLastLogin] = gettime();
    PlayerInfo[playerid][pRegisterDate] = gettime();
    
    // Send welcome message
    SendClientMessage(playerid, COLOR_GREEN, "Registration successful! Welcome to "SERVER_NAME"!");
    SendClientMessage(playerid, COLOR_GREEN, "You are a new survivor. Gather resources to survive and build a base!");
    
    // Set player's spawn info and spawn them
    SetSpawnInfo(playerid, 0, 73, -1867.0 + float(random(3000)), -88.0 + float(random(600)), 15.0, 0.0, 0, 0, 0, 0, 0, 0);
    SpawnPlayer(playerid);
    
    return 1;
}

public OnInventoryLoad(playerid)
{
    new rows, fields;
    cache_get_row_count(rows);
    cache_get_field_count(fields);
    
    for(new i = 0; i < rows; i++)
    {
        new slot = cache_get_field_content_int(i, "slot");
        PlayerInfo[playerid][pInventory][slot] = cache_get_field_content_int(i, "item_id");
        PlayerInfo[playerid][pInventoryAmount][slot] = cache_get_field_content_int(i, "amount");
    }
    
    return 1;
}

GivePlayerBasicKit(playerid)
{
    // Give basic tools and supplies to new players
    PlayerInfo[playerid][pInventory][0] = ITEM_HATCHET;
    PlayerInfo[playerid][pInventoryAmount][0] = 1;
    
    PlayerInfo[playerid][pInventory][1] = ITEM_PICKAXE;
    PlayerInfo[playerid][pInventoryAmount][1] = 1;
    
    PlayerInfo[playerid][pInventory][2] = ITEM_BANDAGE;
    PlayerInfo[playerid][pInventoryAmount][2] = 3;
    
    PlayerInfo[playerid][pInventory][3] = ITEM_FOOD;
    PlayerInfo[playerid][pInventoryAmount][3] = 2;
    
    PlayerInfo[playerid][pInventory][4] = ITEM_WATER;
    PlayerInfo[playerid][pInventoryAmount][4] = 2;
    
    PlayerInfo[playerid][pInventory][5] = ITEM_SLEEPING_BAG;
    PlayerInfo[playerid][pInventoryAmount][5] = 1;
    
    SendClientMessage(playerid, COLOR_GREEN, "You received a starter kit with basic tools and supplies.");
    
    return 1;
}

ShowPlayerInventory(playerid)
{
    new string[1024], itemCount = 0;
    format(string, sizeof(string), "Inventory:\n");
    
    for(new i = 0; i < 30; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] > 0)
        {
            new itemName[32];
            GetItemName(PlayerInfo[playerid][pInventory][i], itemName);
            
            format(string, sizeof(string), "%s%d. %s (x%d)\n", string, i+1, itemName, PlayerInfo[playerid][pInventoryAmount][i]);
            itemCount++;
        }
        else
        {
            format(string, sizeof(string), "%s%d. Empty\n", string, i+1);
        }
    }
    
    if(itemCount == 0)
    {
        format(string, sizeof(string), "%sYour inventory is empty.\n", string);
    }
    
    ShowPlayerDialog(playerid, DIALOG_INVENTORY, DIALOG_STYLE_LIST, "Inventory", string, "Use", "Close");
    
    return 1;
}

ShowCraftingMenu(playerid)
{
    new string[1024];
    format(string, sizeof(string), "Crafting Menu:\n");
    format(string, sizeof(string), "%s1. Hatchet (50 Wood, 25 Metal)\n", string);
    format(string, sizeof(string), "%s2. Pickaxe (50 Wood, 40 Metal)\n", string);
    format(string, sizeof(string), "%s3. Hammer (100 Wood, 50 Metal)\n", string);
    format(string, sizeof(string), "%s4. Bandage (10 Cloth)\n", string);
    format(string, sizeof(string), "%s5. Medkit (50 Cloth, 20 Metal)\n", string);
    format(string, sizeof(string), "%s6. Sleeping Bag (100 Cloth, 30 Wood)\n", string);
    format(string, sizeof(string), "%s7. Furnace (500 Stone, 100 Wood, 50 Metal)\n", string);
    format(string, sizeof(string), "%s8. Campfire (200 Wood, 20 Stone)\n", string);
    format(string, sizeof(string), "%s9. Wooden Door (200 Wood, 50 Metal)\n", string);
    format(string, sizeof(string), "%s10. Metal Door (300 Metal, 50 Wood)\n", string);
    format(string, sizeof(string), "%s11. Code Lock (100 Metal)\n", string);
    format(string, sizeof(string), "%s12. Pistol (150 Metal, 50 Wood, 20 Gunpowder)\n", string);
    format(string, sizeof(string), "%s13. Shotgun (200 Metal, 100 Wood, 30 Gunpowder)\n", string);
    format(string, sizeof(string), "%s14. Rifle (300 Metal, 150 Wood, 50 Gunpowder)\n", string);
    format(string, sizeof(string), "%s15. Pistol Ammo (20 Metal, 10 Gunpowder)\n", string);
    format(string, sizeof(string), "%s16. Shotgun Ammo (30 Metal, 15 Gunpowder)\n", string);
    format(string, sizeof(string), "%s17. Rifle Ammo (40 Metal, 20 Gunpowder)\n", string);
    format(string, sizeof(string), "%s18. Gunpowder (30 Charcoal, 20 Sulfur)\n", string);
    format(string, sizeof(string), "%s19. Explosive (100 Gunpowder, 50 Metal, 20 Cloth)\n", string);
    format(string, sizeof(string), "%s20. C4 (5 Explosive, 100 Metal, 60 Cloth)\n", string);
    
    ShowPlayerDialog(playerid, DIALOG_CRAFTING, DIALOG_STYLE_LIST, "Crafting Menu", string, "Craft", "Close");
    
    return 1;
}

ShowBuildingMenu(playerid)
{
    // Check if player has hammer
    new bool:hasHammer = false;
    
    for(new i = 0; i < 30; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] == ITEM_HAMMER)
        {
            hasHammer = true;
            break;
        }
    }
    
    if(!hasHammer)
    {
        SendClientMessage(playerid, COLOR_RED, "You need a hammer to build! Craft one first.");
        return 0;
    }
    
    new string[512];
    format(string, sizeof(string), "Building Menu:\n");
    format(string, sizeof(string), "%s1. Foundation (500 Wood, 300 Stone)\n", string);
    format(string, sizeof(string), "%s2. Wall (200 Wood, 100 Stone)\n", string);
    format(string, sizeof(string), "%s3. Doorway (180 Wood, 90 Stone)\n", string);
    format(string, sizeof(string), "%s4. Floor (150 Wood, 80 Stone)\n", string);
    format(string, sizeof(string), "%s5. Ceiling (150 Wood, 80 Stone)\n", string);
    format(string, sizeof(string), "%s6. Stairs (250 Wood, 150 Stone)\n", string);
    format(string, sizeof(string), "%s7. Window (160 Wood, 80 Stone)\n", string);
    format(string, sizeof(string), "%s8. Storage Box (100 Wood, 20 Metal)\n", string);
    
    ShowPlayerDialog(playerid, DIALOG_BUILDING, DIALOG_STYLE_LIST, "Building Menu", string, "Build", "Close");
    
    return 1;
}

ShowHelpMenu(playerid)
{
    new string[1024];
    format(string, sizeof(string), "Help Menu - "SERVER_NAME"\n\n");
    format(string, sizeof(string), "%sBasic Controls:\n", string);
    format(string, sizeof(string), "%s- Y: Open Inventory\n", string);
    format(string, sizeof(string), "%s- N: Open Crafting Menu\n", string);
    format(string, sizeof(string), "%s- H: Show Help Menu\n", string);
    format(string, sizeof(string), "%s- Left Click: Hit/Gather Resources\n", string);
    format(string, sizeof(string), "%s- Right Click: Interact/Place Building\n\n", string);
    
    format(string, sizeof(string), "%sBasic Commands:\n", string);
    format(string, sizeof(string), "%s- /inventory - View your inventory\n", string);
    format(string, sizeof(string), "%s- /craft - Open crafting menu\n", string);
    format(string, sizeof(string), "%s- /build - Open building menu\n", string);
    format(string, sizeof(string), "%s- /drop [slot] [amount] - Drop item on ground\n", string);
    format(string, sizeof(string), "%s- /stats - View your statistics\n", string);
    format(string, sizeof(string), "%s- /resources - View your resources\n", string);
    format(string, sizeof(string), "%s- /menu - Show main menu\n", string);
    format(string, sizeof(string), "%s- /suicide - Kill yourself\n\n", string);
    
    format(string, sizeof(string), "%sSurvival Tips:\n", string);
    format(string, sizeof(string), "%s- Gather wood and stone to build a base\n", string);
    format(string, sizeof(string), "%s- Always keep food and water with you\n", string);
    format(string, sizeof(string), "%s- Avoid radiation zones without proper protection\n", string);
    format(string, sizeof(string), "%s- Place a sleeping bag to set your spawn point\n", string);
    format(string, sizeof(string), "%s- Lock your doors to prevent raiders\n", string);
    format(string, sizeof(string), "%s- Team up with other players for better chances of survival\n", string);
    
    ShowPlayerDialog(playerid, DIALOG_STYLE_MSGBOX, "Help Menu", string, "Close", "");
    
    return 1;
}

ShowPlayerMenu(playerid)
{
    new string[256];
    format(string, sizeof(string), "Player Menu:\n");
    format(string, sizeof(string), "%s1. View Statistics\n", string);
    format(string, sizeof(string), "%s2. Inventory\n", string);
    format(string, sizeof(string), "%s3. Crafting\n", string);
    format(string, sizeof(string), "%s4. Building\n", string);
    format(string, sizeof(string), "%s5. Help\n", string);
    
    if(PlayerInfo[playerid][pAdmin] >= 1)
    {
        format(string, sizeof(string), "%s6. Admin Panel\n", string);
    }
    
    ShowPlayerDialog(playerid, DIALOG_PLAYER_MENU, DIALOG_STYLE_LIST, "Player Menu", string, "Select", "Close");
    
    return 1;
}

ShowAdminMenu(playerid)
{
    if(PlayerInfo[playerid][pAdmin] < 1) return 0;
    
    new string[512];
    format(string, sizeof(string), "Admin Menu - Level %d\n", PlayerInfo[playerid][pAdmin]);
    format(string, sizeof(string), "%s1. Teleport to Coordinates\n", string);
    format(string, sizeof(string), "%s2. Spawn Item\n", string);
    format(string, sizeof(string), "%s3. Spawn Resource\n", string);
    format(string, sizeof(string), "%s4. Kill Player\n", string);
    format(string, sizeof(string), "%s5. Reset Server\n", string);
    format(string, sizeof(string), "%s6. Set Admin Level\n", string);
    
    ShowPlayerDialog(playerid, DIALOG_ADMIN, DIALOG_STYLE_LIST, "Admin Menu", string, "Select", "Close");
    
    return 1;
}

ShowLootContainer(playerid, lootid)
{
    if(lootid < 0 || lootid >= LootCount || !LootInfo[lootid][lootActive])
    {
        SendClientMessage(playerid, COLOR_RED, "This container is no longer available!");
        return 0;
    }
    
    new string[512];
    new containerType[32];
    
    switch(LootInfo[lootid][lootType])
    {
        case 0: containerType = "Barrel";
        case 1: containerType = "Crate";
        case 2: containerType = "Military Crate";
        case 3: containerType = "Elite Crate";
        case 4: containerType = "Dead Body";
        default: containerType = "Container";
    }
    
    format(string, sizeof(string), "%s Contents:\n", containerType);
    
    for(new i = 0; i < 10; i++)
    {
        if(LootInfo[lootid][lootItems][i] > 0)
        {
            new itemName[32];
            GetItemName(LootInfo[lootid][lootItems][i], itemName);
            
            format(string, sizeof(string), "%s%d. %s (x%d)\n", string, i+1, itemName, LootInfo[lootid][lootItemsAmount][i]);
        }
        else
        {
            format(string, sizeof(string), "%s%d. Empty\n", string, i+1);
        }
    }
    
    PlayerInfo[playerid][pLootingID] = lootid;
    ShowPlayerDialog(playerid, DIALOG_LOOT, DIALOG_STYLE_LIST, containerType, string, "Take", "Close");
    
    return 1;
}

UpdatePlayerHUDInfo(playerid)
{
    // Update progress bars
    SetProgressBarValue(PlayerInfo[playerid][pProgressBar], PlayerInfo[playerid][pHealth]);
    SetProgressBarValue(PlayerInfo[playerid][pHungerBar], PlayerInfo[playerid][pHunger]);
    SetProgressBarValue(PlayerInfo[playerid][pThirstBar], PlayerInfo[playerid][pThirst]);
    SetProgressBarValue(PlayerInfo[playerid][pRadiationBar], PlayerInfo[playerid][pRadiation]);
    
    // Set progress bar colors based on value
    if(PlayerInfo[playerid][pHealth] > 75.0)
        SetProgressBarColour(PlayerInfo[playerid][pProgressBar], COLOR_GREEN);
    else if(PlayerInfo[playerid][pHealth] > 25.0)
        SetProgressBarColour(PlayerInfo[playerid][pProgressBar], COLOR_YELLOW);
    else
        SetProgressBarColour(PlayerInfo[playerid][pProgressBar], COLOR_RED);
        
    if(PlayerInfo[playerid][pHunger] > 75.0)
        SetProgressBarColour(PlayerInfo[playerid][pHungerBar], COLOR_GREEN);
    else if(PlayerInfo[playerid][pHunger] > 25.0)
        SetProgressBarColour(PlayerInfo[playerid][pHungerBar], COLOR_ORANGE);
    else
        SetProgressBarColour(PlayerInfo[playerid][pHungerBar], COLOR_RED);
        
    if(PlayerInfo[playerid][pThirst] > 75.0)
        SetProgressBarColour(PlayerInfo[playerid][pThirstBar], COLOR_BLUE);
    else if(PlayerInfo[playerid][pThirst] > 25.0)
        SetProgressBarColour(PlayerInfo[playerid][pThirstBar], COLOR_PURPLE);
    else
        SetProgressBarColour(PlayerInfo[playerid][pThirstBar], COLOR_RED);
        
    // Update text drawn info
    new string[128];
    format(string, sizeof(string), "Health: %.1f", PlayerInfo[playerid][pHealth]);
    PlayerTextDrawSetString(playerid, PlayerInfo[playerid][pProgressBar], string);
    
    format(string, sizeof(string), "Hunger: %.1f", PlayerInfo[playerid][pHunger]);
    PlayerTextDrawSetString(playerid, PlayerInfo[playerid][pHungerBar], string);
    
    format(string, sizeof(string), "Thirst: %.1f", PlayerInfo[playerid][pThirst]);
    PlayerTextDrawSetString(playerid, PlayerInfo[playerid][pThirstBar], string);
    
    format(string, sizeof(string), "Radiation: %.1f", PlayerInfo[playerid][pRadiation]);
    PlayerTextDrawSetString(playerid, PlayerInfo[playerid][pRadiationBar], string);
    
    return 1;
}

CreateRadiationZones()
{
    // Create radiation zones in dangerous areas
    RadiationZones[0][radX] = 2000.0;
    RadiationZones[0][radY] = 2000.0;
    RadiationZones[0][radZ] = 0.0;
    RadiationZones[0][radRadius] = 500.0;
    RadiationZones[0][radLevel] = 3;
    
    RadiationZones[1][radX] = -2000.0;
    RadiationZones[1][radY] = 1500.0;
    RadiationZones[1][radZ] = 0.0;
    RadiationZones[1][radRadius] = 300.0;
    RadiationZones[1][radLevel] = 2;
    
    RadiationZones[2][radX] = 0.0;
    RadiationZones[2][radY] = -2000.0;
    RadiationZones[2][radZ] = 0.0;
    RadiationZones[2][radRadius] = 400.0;
    RadiationZones[2][radLevel] = 4;
    
    RadiationZoneCount = 3;
    
    // Create map icons for radiation zones
    for(new i = 0; i < RadiationZoneCount; i++)
    {
        CreateDynamicMapIcon(RadiationZones[i][radX], RadiationZones[i][radY], RadiationZones[i][radZ], 23, 0, -1, -1, -1, 1000.0);
    }
    
    return 1;
}

public CheckRadiationExposure(playerid)
{
    // Check if player is in a radiation zone
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    new bool:inRadZone = false;
    new radLevel = 0;
    
    for(new i = 0; i < RadiationZoneCount; i++)
    {
        new Float:distance = GetDistanceBetweenPoints3D(x, y, z, RadiationZones[i][radX], RadiationZones[i][radY], RadiationZones[i][radZ]);
        
        if(distance < RadiationZones[i][radRadius])
        {
            inRadZone = true;
            radLevel = RadiationZones[i][radLevel];
            break;
        }
    }
    
    if(inRadZone)
    {
        // Check if player has radiation protection
        new bool:hasProtection = false;
        
        // Check if player is wearing radiation suit (specific skin ID)
        if(GetPlayerSkin(playerid) == 285) // Hazmat suit skin
        {
            hasProtection = true;
        }
        
        if(!hasProtection)
        {
            // Apply radiation damage based on level
            PlayerInfo[playerid][pRadiation] += 0.1 * radLevel;
            
            if(PlayerInfo[playerid][pRadiation] > 100.0)
                PlayerInfo[playerid][pRadiation] = 100.0;
                
            // Apply health damage at high radiation
            if(PlayerInfo[playerid][pRadiation] > 50.0)
            {
                new Float:health;
                GetPlayerHealth(playerid, health);
                health -= 0.5 * (PlayerInfo[playerid][pRadiation] / 50.0);
                
                if(health <= 0.0)
                {
                    SetPlayerHealth(playerid, 0.0);
                }
                else
                {
                    SetPlayerHealth(playerid, health);
                    PlayerInfo[playerid][pHealth] = health;
                }
            }
            
            // Warn player about radiation
            if(GetTickCount() % 5000 < 50) // Only warn every ~5 seconds
            {
                new string[128];
                format(string, sizeof(string), "WARNING: You are in a radiation zone (Level %d)! Your radiation level: %.1f", radLevel, PlayerInfo[playerid][pRadiation]);
                SendClientMessage(playerid, COLOR_YELLOW, string);
            }
        }
    }
    else
    {
        // Slowly reduce radiation when not in zone
        if(PlayerInfo[playerid][pRadiation] > 0.0)
        {
            PlayerInfo[playerid][pRadiation] -= 0.05;
            
            if(PlayerInfo[playerid][pRadiation] < 0.0)
                PlayerInfo[playerid][pRadiation] = 0.0;
        }
    }
    
    return 1;
}

SpawnAllResources()
{
    print("Spawning resources...");
    
    // Spawn trees (wood)
    for(new i = 0; i < 400; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        // Avoid spawning in water (simple check)
        if(z < 5.0) z = 5.0;
        
        CreateResourceAtPos(0, x, y, z);
    }
    
    // Spawn rocks (stone)
    for(new i = 0; i < 300; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        // Avoid spawning in water (simple check)
        if(z < 5.0) z = 5.0;
        
        CreateResourceAtPos(1, x, y, z);
    }
    
    // Spawn metal nodes
    for(new i = 0; i < 200; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        // Avoid spawning in water (simple check)
        if(z < 5.0) z = 5.0;
        
        CreateResourceAtPos(2, x, y, z);
    }
    
    // Spawn hemp plants (cloth)
    for(new i = 0; i < 150; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        // Avoid spawning in water (simple check)
        if(z < 5.0) z = 5.0;
        
        CreateResourceAtPos(3, x, y, z);
    }
    
    printf("Spawned %d resources", ResourceCount);
    
    return 1;
}

CreateResourceAtPos(type, Float:x, Float:y, Float:z)
{
    if(ResourceCount >= MAX_RESOURCES) return -1;
    
    ResourceInfo[ResourceCount][resType] = type;
    ResourceInfo[ResourceCount][resX] = x;
    ResourceInfo[ResourceCount][resY] = y;
    ResourceInfo[ResourceCount][resZ] = z;
    ResourceInfo[ResourceCount][resRX] = 0.0;
    ResourceInfo[ResourceCount][resRY] = 0.0;
    ResourceInfo[ResourceCount][resRZ] = float(random(360));
    
    switch(type)
    {
        case 0: // Wood
        {
            ResourceInfo[ResourceCount][resAmount] = 100 + random(200);
            ResourceInfo[ResourceCount][resHealth] = 100;
            ResourceInfo[ResourceCount][resObject] = CreateDynamicObject(618, x, y, z, 0.0, 0.0, float(random(360)), -1, -1, -1, 300.0);
        }
        case 1: // Stone
        {
            ResourceInfo[ResourceCount][resAmount] = 80 + random(120);
            ResourceInfo[ResourceCount][resHealth] = 150;
            ResourceInfo[ResourceCount][resObject] = CreateDynamicObject(3929, x, y, z, 0.0, 0.0, float(random(360)), -1, -1, -1, 300.0);
        }
        case 2: // Metal
        {
            ResourceInfo[ResourceCount][resAmount] = 50 + random(100);
            ResourceInfo[ResourceCount][resHealth] = 200;
            ResourceInfo[ResourceCount][resObject] = CreateDynamicObject(3930, x, y, z, 0.0, 0.0, float(random(360)), -1, -1, -1, 300.0);
        }
        case 3: // Hemp/Cloth
        {
            ResourceInfo[ResourceCount][resAmount] = 30 + random(50);
            ResourceInfo[ResourceCount][resHealth] = 50;
            ResourceInfo[ResourceCount][resObject] = CreateDynamicObject(19473, x, y, z, 0.0, 0.0, float(random(360)), -1, -1, -1, 300.0);
        }
    }
    
    ResourceInfo[ResourceCount][resActive] = true;
    ResourceInfo[ResourceCount][resRespawnTime] = 300 + random(300); // 5-10 minutes
    
    ResourceCount++;
    
    return ResourceCount - 1;
}

GatherResource(playerid)
{
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    // Find nearest resource
    new resourceid = -1;
    new Float:minDist = 3.0;
    
    for(new i = 0; i < ResourceCount; i++)
    {
        if(!ResourceInfo[i][resActive]) continue;
        
        new Float:dist = GetDistanceBetweenPoints3D(x, y, z, ResourceInfo[i][resX], ResourceInfo[i][resY], ResourceInfo[i][resZ]);
        if(dist < minDist)
        {
            minDist = dist;
            resourceid = i;
        }
    }
    
    if(resourceid == -1)
    {
        return 0;
    }
    
    // Check if player has the right tool in inventory
    new bool:hasTool = false;
    new toolDamage = 1;
    
    switch(ResourceInfo[resourceid][resType])
    {
        case 0: // Wood - need hatchet
        {
            for(new i = 0; i < 30; i++)
            {
                if(PlayerInfo[playerid][pInventory][i] == ITEM_HATCHET) // Hatchet
                {
                    hasTool = true;
                    toolDamage = 10;
                    break;
                }
            }
        }
        case 1, 2: // Stone/Metal - need pickaxe
        {
            for(new i = 0; i < 30; i++)
            {
                if(PlayerInfo[playerid][pInventory][i] == ITEM_PICKAXE) // Pickaxe
                {
                    hasTool = true;
                    toolDamage = 8;
                    break;
                }
            }
        }
        case 3: // Hemp - can gather with hands
        {
            hasTool = true;
            toolDamage = 5;
        }
    }
    
    // If no tool, can still gather but at reduced efficiency
    if(!hasTool)
    {
        toolDamage = 1;
    }
    
    // Hit resource
    UpdateResourceHealth(resourceid, playerid, toolDamage);
    
    // Show animation
    ApplyAnimation(playerid, "BASEBALL", "Bat_4", 4.1, 0, 0, 0, 0, 0, 1);
    
    return 1;
}

public UpdateResourceHealth(resourceid, playerid, damage)
{
    if(resourceid < 0 || resourceid >= ResourceCount) return 0;
    if(!ResourceInfo[resourceid][resActive]) return 0;
    
    // Reduce resource health
    ResourceInfo[resourceid][resHealth] -= damage;
    
    if(ResourceInfo[resourceid][resHealth] <= 0)
    {
        // Resource depleted, give rewards
        new amount;
        
        switch(ResourceInfo[resourceid][resType])
        {
            case 0: // Wood
            {
                amount = 5 + random(10);
                PlayerInfo[playerid][pMaterials][0] += amount;
                
                // Small chance to get cloth from trees
                if(random(10) == 0)
                {
                    PlayerInfo[playerid][pMaterials][3] += 1 + random(3);
                    SendClientMessage(playerid, COLOR_GREEN, "You found some cloth in the tree!");
                }
            }
            case 1: // Stone
            {
                amount = 5 + random(8);
                PlayerInfo[playerid][pMaterials][1] += amount;
                
                // Small chance to get metal from stone
                if(random(5) == 0)
                {
                    PlayerInfo[playerid][pMaterials][2] += 1 + random(2);
                    SendClientMessage(playerid, COLOR_GREEN, "You found some metal ore in the rock!");
                }
            }
            case 2: // Metal
            {
                amount = 3 + random(5);
                PlayerInfo[playerid][pMaterials][2] += amount;
                
                // Chance to get sulfur or high quality metal
                if(random(3) == 0)
                {
                    new slot = FindFreeInventorySlot(playerid, ITEM_SULFUR);
                    if(slot != -1)
                    {
                        if(PlayerInfo[playerid][pInventory][slot] == 0)
                        {
                            PlayerInfo[playerid][pInventory][slot] = ITEM_SULFUR;
                            PlayerInfo[playerid][pInventoryAmount][slot] = 1 + random(3);
                        }
                        else
                        {
                            PlayerInfo[playerid][pInventoryAmount][slot] += 1 + random(3);
                        }
                        SendClientMessage(playerid, COLOR_GREEN, "You found some sulfur in the ore!");
                    }
                }
            }
            case 3: // Hemp
            {
                amount = 5 + random(10);
                PlayerInfo[playerid][pMaterials][3] += amount; // Cloth
            }
        }
        
        // Show message
        new message[128];
        new resourceName[10];
        switch(ResourceInfo[resourceid][resType])
        {
            case 0: resourceName = "wood";
            case 1: resourceName = "stone";
            case 2: resourceName = "metal";
            case 3: resourceName = "cloth";
        }
        
        format(message, sizeof(message), "You gathered %d %s. You now have %d %s.", 
            amount, 
            resourceName, 
            PlayerInfo[playerid][pMaterials][ResourceInfo[resourceid][resType]], 
            resourceName
        );
        SendClientMessage(playerid, COLOR_GREEN, message);
        
        // Remove resource temporarily
        ResourceInfo[resourceid][resActive] = false;
        DestroyDynamicObject(ResourceInfo[resourceid][resObject]);
        
        // Set respawn timer
        SetTimerEx("RespawnResource", ResourceInfo[resourceid][resRespawnTime] * 1000, false, "i", resourceid);
    }
    else
    {
        // Resource hit but not depleted, give small amount
        if(random(3) == 0) // 1/3 chance to get resource on hit
        {
            new amount = 1 + random(2);
            PlayerInfo[playerid][pMaterials][ResourceInfo[resourceid][resType]] += amount;
            
            // Show message
            new message[128];
            new resourceName[10];
            switch(ResourceInfo[resourceid][resType])
            {
                case 0: resourceName = "wood";
                case 1: resourceName = "stone";
                case 2: resourceName = "metal";
                case 3: resourceName = "cloth";
            }
            
            format(message, sizeof(message), "You gathered %d %s.", amount, resourceName);
            SendClientMessage(playerid, COLOR_GREEN, message);
        }
    }
    
    return 1;
}

public RespawnResource(resourceid)
{
    if(resourceid < 0 || resourceid >= ResourceCount) return 0;
    
    // Reset resource health
    switch(ResourceInfo[resourceid][resType])
    {
        case 0: ResourceInfo[resourceid][resHealth] = 100;
        case 1: ResourceInfo[resourceid][resHealth] = 150;
        case 2: ResourceInfo[resourceid][resHealth] = 200;
        case 3: ResourceInfo[resourceid][resHealth] = 50;
    }
    
    // Reset amount
    switch(ResourceInfo[resourceid][resType])
    {
        case 0: ResourceInfo[resourceid][resAmount] = 100 + random(200);
        case 1: ResourceInfo[resourceid][resAmount] = 80 + random(120);
        case 2: ResourceInfo[resourceid][resAmount] = 50 + random(100);
        case 3: ResourceInfo[resourceid][resAmount] = 30 + random(50);
    }
    
    // Create object
    switch(ResourceInfo[resourceid][resType])
    {
        case 0: // Wood
        {
            ResourceInfo[resourceid][resObject] = CreateDynamicObject(618, 
                ResourceInfo[resourceid][resX], 
                ResourceInfo[resourceid][resY], 
                ResourceInfo[resourceid][resZ], 
                ResourceInfo[resourceid][resRX], 
                ResourceInfo[resourceid][resRY], 
                ResourceInfo[resourceid][resRZ], 
                -1, -1, -1, 300.0);
        }
        case 1: // Stone
        {
            ResourceInfo[resourceid][resObject] = CreateDynamicObject(3929, 
                ResourceInfo[resourceid][resX], 
                ResourceInfo[resourceid][resY], 
                ResourceInfo[resourceid][resZ], 
                ResourceInfo[resourceid][resRX], 
                ResourceInfo[resourceid][resRY], 
                ResourceInfo[resourceid][resRZ], 
                -1, -1, -1, 300.0);
        }
        case 2: // Metal
        {
            ResourceInfo[resourceid][resObject] = CreateDynamicObject(3930, 
                ResourceInfo[resourceid][resX], 
                ResourceInfo[resourceid][resY], 
                ResourceInfo[resourceid][resZ], 
                ResourceInfo[resourceid][resRX], 
                ResourceInfo[resourceid][resRY], 
                ResourceInfo[resourceid][resRZ], 
                -1, -1, -1, 300.0);
        }
        case 3: // Hemp
        {
            ResourceInfo[resourceid][resObject] = CreateDynamicObject(19473, 
                ResourceInfo[resourceid][resX], 
                ResourceInfo[resourceid][resY], 
                ResourceInfo[resourceid][resZ], 
                ResourceInfo[resourceid][resRX], 
                ResourceInfo[resourceid][resRY], 
                ResourceInfo[resourceid][resRZ], 
                -1, -1, -1, 300.0);
        }
    }
    
    ResourceInfo[resourceid][resActive] = true;
    
    return 1;
}

public LoadBuildings()
{
    new query[128];
    mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM buildings");
    mysql_tquery(g_SQL, query, "OnBuildingsLoad", "");
    
    return 1;
}

public OnBuildingsLoad()
{
    new rows, fields;
    cache_get_row_count(rows);
    cache_get_field_count(fields);
    
    printf("Loading %d buildings from database...", rows);
    
    for(new i = 0; i < rows; i++)
    {
        if(i >= MAX_BUILDINGS) break;
        
        BuildingInfo[i][buildID] = cache_get_field_content_int(i, "id");
        BuildingInfo[i][buildOwner] = cache_get_field_content_int(i, "owner");
        BuildingInfo[i][buildType] = cache_get_field_content_int(i, "type");
        BuildingInfo[i][buildX] = cache_get_field_content_float(i, "x");
        BuildingInfo[i][buildY] = cache_get_field_content_float(i, "y");
        BuildingInfo[i][buildZ] = cache_get_field_content_float(i, "z");
        BuildingInfo[i][buildRX] = cache_get_field_content_float(i, "rx");
        BuildingInfo[i][buildRY] = cache_get_field_content_float(i, "ry");
        BuildingInfo[i][buildRZ] = cache_get_field_content_float(i, "rz");
        BuildingInfo[i][buildHealth] = cache_get_field_content_int(i, "health");
        BuildingInfo[i][buildMaxHealth] = cache_get_field_content_int(i, "maxhealth");
        
        cache_get_field_content(i, "lockcode", BuildingInfo[i][buildLockCode], g_SQL, 10);
        BuildingInfo[i][buildLocked] = cache_get_field_content_int(i, "locked");
        
        // Create building object
        new objectid;
        switch(BuildingInfo[i][buildType])
        {
            case 0: objectid = 19380; // Foundation
            case 1: objectid = 19353; // Wall
            case 2: objectid = 19454; // Doorway
            case 3: objectid = 19302; // Door
            case 4: objectid = 19366; // Floor
            case 5: objectid = 19445; // Ceiling
            case 6: objectid = 19423; // Stairs
            case 7: objectid = 19377; // Window
            case 8: objectid = 2969;  // Chest/Storage
            case 16: objectid = 1279; // Sleeping Bag
            case 17: objectid = 3525; // Furnace
            case 18: objectid = 19632; // Campfire
            default: objectid = 19353; // Default to wall
        }
        
        BuildingInfo[i][buildObject] = CreateDynamicObject(objectid, 
            BuildingInfo[i][buildX], 
            BuildingInfo[i][buildY], 
            BuildingInfo[i][buildZ], 
            BuildingInfo[i][buildRX], 
            BuildingInfo[i][buildRY], 
            BuildingInfo[i][buildRZ], 
            -1, -1);
            
        // Load building items if it's a storage
        if(BuildingInfo[i][buildType] == 8 || BuildingInfo[i][buildType] == 17 || BuildingInfo[i][buildType] == 18)
        {
            // Clear item slots
            for(new j = 0; j < 20; j++)
            {
                BuildingInfo[i][buildItemID][j] = 0;
                BuildingInfo[i][buildItemAmount][j] = 0;
            }
            
            // Query items
            new itemQuery[128];
            mysql_format(g_SQL, itemQuery, sizeof(itemQuery), "SELECT * FROM building_items WHERE building_id = %d", BuildingInfo[i][buildID]);
            mysql_tquery(g_SQL, itemQuery, "OnBuildingItemsLoad", "i", i);
        }
        
        BuildingCount++;
    }
    
    printf("Loaded %d buildings", BuildingCount);
    
    return 1;
}

forward OnBuildingItemsLoad(buildingid);
public OnBuildingItemsLoad(buildingid)
{
    new rows, fields;
    cache_get_row_count(rows);
    cache_get_field_count(fields);
    
    for(new i = 0; i < rows; i++)
    {
        new slot = cache_get_field_content_int(i, "slot");
        if(slot >= 0 && slot < 20)
        {
            BuildingInfo[buildingid][buildItemID][slot] = cache_get_field_content_int(i, "item_id");
            BuildingInfo[buildingid][buildItemAmount][slot] = cache_get_field_content_int(i, "amount");
        }
    }
    
    return 1;
}

PlaceBuilding(playerid)
{
    if(!PlayerInfo[playerid][pBuildingMode]) return 0;
    
    new buildingType = PlayerInfo[playerid][pBuildingType];
    
    // Get position for building
    new Float:x, Float:y, Float:z, Float:angle;
    GetPlayerPos(playerid, x, y, z);
    GetPlayerFacingAngle(playerid, angle);
    
    // Calculate position in front of player
    x += (2.0 * floatsin(-angle, degrees));
    y += (2.0 * floatcos(-angle, degrees));
    
    // Apply rotation if set
    angle += PlayerInfo[playerid][pBuildingRotation];
    if(angle >= 360.0) angle -= 360.0;
    
    // Find free building slot
    new buildingid = -1;
    
    for(new i = 0; i < MAX_BUILDINGS; i++)
    {
        if(!IsValidDynamicObject(BuildingInfo[i][buildObject]))
        {
            buildingid = i;
            break;
        }
    }
    
    if(buildingid == -1)
    {
        SendClientMessage(playerid, COLOR_RED, "Maximum buildings reached on server!");
        PlayerInfo[playerid][pBuildingMode] = 0;
        return 0;
    }
    
    // Check if placement is valid (not colliding with other buildings)
    for(new i = 0; i < BuildingCount; i++)
    {
        if(IsValidDynamicObject(BuildingInfo[i][buildObject]) && 
           GetDistanceBetweenPoints3D(x, y, z, BuildingInfo[i][buildX], BuildingInfo[i][buildY], BuildingInfo[i][buildZ]) < 1.0)
        {
            SendClientMessage(playerid, COLOR_RED, "Cannot place building here - too close to another structure!");
            return 0;
        }
    }
    
    // Create building object
    new objectid;
    new maxHealth;
    
    switch(buildingType)
    {
        case 0: // Foundation
        {
            objectid = 19380;
            maxHealth = 1000;
        }
        case 1: // Wall
        {
            objectid = 19353;
            maxHealth = 500;
        }
        case 2: // Doorway
        {
            objectid = 19454;
            maxHealth = 500;
        }
        case 3: // Door
        {
            objectid = 19302;
            maxHealth = 300;
        }
        case 4: // Floor
        {
            objectid = 19366;
            maxHealth = 400;
        }
        case 5: // Ceiling
        {
            objectid = 19445;
            maxHealth = 400;
        }
        case 6: // Stairs
        {
            objectid = 19423;
            maxHealth = 600;
        }
        case 7: // Window
        {
            objectid = 19377;
            maxHealth = 200;
        }
        case 8: // Storage Box
        {
            objectid = 2969;
            maxHealth = 100;
        }
        case 16: // Sleeping Bag
        {
            objectid = 1279;
            maxHealth = 50;
        }
        case 17: // Furnace
        {
            objectid = 3525;
            maxHealth = 200;
        }
        case 18: // Campfire
        {
            objectid = 19632;
            maxHealth = 100;
        }
        case 22: // Wooden Door
        {
            objectid = 19302;
            maxHealth = 300;
        }
        case 23: // Metal Door
        {
            objectid = 19302;
            maxHealth = 500;
        }
        default:
        {
            objectid = 19353; // Default to wall
            maxHealth = 500;
        }
    }
    
    BuildingInfo[buildingid][buildOwner] = PlayerInfo[playerid][pID];
    BuildingInfo[buildingid][buildType] = buildingType;
    BuildingInfo[buildingid][buildX] = x;
    BuildingInfo[buildingid][buildY] = y;
    BuildingInfo[buildingid][buildZ] = z;
    BuildingInfo[buildingid][buildRX] = 0.0;
    BuildingInfo[buildingid][buildRY] = 0.0;
    BuildingInfo[buildingid][buildRZ] = angle;
    BuildingInfo[buildingid][buildHealth] = maxHealth;
    BuildingInfo[buildingid][buildMaxHealth] = maxHealth;
    BuildingInfo[buildingid][buildLockCode][0] = '\0';
    BuildingInfo[buildingid][buildLocked] = 0;
    
    // Clear items if storage
    if(buildingType == 8 || buildingType == 17 || buildingType == 18)
    {
        for(new i = 0; i < 20; i++)
        {
            BuildingInfo[buildingid][buildItemID][i] = 0;
            BuildingInfo[buildingid][buildItemAmount][i] = 0;
        }
    }
    
    BuildingInfo[buildingid][buildObject] = CreateDynamicObject(objectid, 
        BuildingInfo[buildingid][buildX], 
        BuildingInfo[buildingid][buildY], 
        BuildingInfo[buildingid][buildZ], 
        BuildingInfo[buildingid][buildRX], 
        BuildingInfo[buildingid][buildRY], 
        BuildingInfo[buildingid][buildRZ], 
        -1, -1);
        
    // Special handling for sleeping bag
    if(buildingType == 16)
    {
        PlayerInfo[playerid][pSpawnPoint] = 1; // Set to spawn at sleeping bag
        SendClientMessage(playerid, COLOR_GREEN, "Sleeping bag placed! You will now spawn here when you die or reconnect.");
    }
    
    // Save building to database
    new query[256];
    mysql_format(g_SQL, query, sizeof(query), 
        "INSERT INTO buildings (owner, type, x, y, z, rx, ry, rz, health, maxhealth, lockcode, locked) VALUES (%d, %d, %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %d, %d, '', 0)",
        BuildingInfo[buildingid][buildOwner],
        BuildingInfo[buildingid][buildType],
        BuildingInfo[buildingid][buildX],
        BuildingInfo[buildingid][buildY],
        BuildingInfo[buildingid][buildZ],
        BuildingInfo[buildingid][buildRX],
        BuildingInfo[buildingid][buildRY],
        BuildingInfo[buildingid][buildRZ],
        BuildingInfo[buildingid][buildHealth],
        BuildingInfo[buildingid][buildMaxHealth]
    );
    mysql_tquery(g_SQL, query, "OnBuildingSave", "i", buildingid);
    
    // Disable building mode
    PlayerInfo[playerid][pBuildingMode] = 0;
    
    // Update building count
    if(buildingid + 1 > BuildingCount)
        BuildingCount = buildingid + 1;
    
    // Send message
    new buildingName[32];
    GetBuildingName(buildingType, buildingName);
    
    new string[128];
    format(string, sizeof(string), "%s placed successfully!", buildingName);
    SendClientMessage(playerid, COLOR_GREEN, string);
    
    return 1;
}

forward OnBuildingSave(buildingid);
public OnBuildingSave(buildingid)
{
    if(buildingid < 0 || buildingid >= MAX_BUILDINGS) return 0;
    
    BuildingInfo[buildingid][buildID] = cache_insert_id();
    
    return 1;
}

InteractWithBuilding(playerid)
{
    // Find closest building
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    new buildingid = -1;
    new Float:minDist = 3.0;
    
    for(new i = 0; i < BuildingCount; i++)
    {
        if(!IsValidDynamicObject(BuildingInfo[i][buildObject])) continue;
        
        new Float:dist = GetDistanceBetweenPoints3D(x, y, z, BuildingInfo[i][buildX], BuildingInfo[i][buildY], BuildingInfo[i][buildZ]);
        if(dist < minDist)
        {
            minDist = dist;
            buildingid = i;
        }
    }
    
    if(buildingid == -1) return 0;
    
    // Handle interaction based on building type
    switch(BuildingInfo[buildingid][buildType])
    {
        case 3, 22, 23: // Door types
        {
            // Check if door is locked
            if(BuildingInfo[buildingid][buildLocked] && BuildingInfo[buildingid][buildOwner] != PlayerInfo[playerid][pID])
            {
                // Check if player has code lock
                ShowPlayerDialog(playerid, DIALOG_STYLE_INPUT, "Enter Door Code", "This door is locked. Enter the code to unlock:", "Submit", "Cancel");
                SetPVarInt(playerid, "InteractingBuildingID", buildingid);
                return 1;
            }
            
            // Toggle door open/closed
            new Float:zRot = BuildingInfo[buildingid][buildRZ];
            
            if(GetPVarInt(playerid, "DoorOpen") == 0)
            {
                zRot += 90.0;
                SetPVarInt(playerid, "DoorOpen", 1);
            }
            else
            {
                zRot -= 90.0;
                SetPVarInt(playerid, "DoorOpen", 0);
            }
            
            SetDynamicObjectRot(BuildingInfo[buildingid][buildObject], 
                BuildingInfo[buildingid][buildRX], 
                BuildingInfo[buildingid][buildRY], 
                zRot);
                
            // Play door sound
            PlayerPlaySound(playerid, 1052, 0.0, 0.0, 0.0);
        }
        
        case 8: // Storage Box
        {
            // Check if owned by player or unlocked
            if(BuildingInfo[buildingid][buildOwner] != PlayerInfo[playerid][pID] && BuildingInfo[buildingid][buildLocked])
            {
                SendClientMessage(playerid, COLOR_RED, "This storage box is locked!");
                return 1;
            }
            
            // Show storage menu
            ShowStorageMenu(playerid, buildingid);
        }
        
        case 17: // Furnace
        {
            // Check if owned by player or unlocked
            if(BuildingInfo[buildingid][buildOwner] != PlayerInfo[playerid][pID] && BuildingInfo[buildingid][buildLocked])
            {
                SendClientMessage(playerid, COLOR_RED, "This furnace is locked!");
                return 1;
            }
            
            // Show furnace menu
            ShowFurnaceMenu(playerid, buildingid);
        }
        
        case 18: // Campfire
        {
            // Show campfire menu
            ShowCampfireMenu(playerid, buildingid);
        }
    }
    
    return 1;
}

ShowStorageMenu(playerid, buildingid)
{
    if(buildingid < 0 || buildingid >= BuildingCount) return 0;
    if(!IsValidDynamicObject(BuildingInfo[buildingid][buildObject])) return 0;
    
    new string[1024];
    format(string, sizeof(string), "Storage Box Contents:\n");
    
    for(new i = 0; i < 20; i++)
    {
        if(BuildingInfo[buildingid][buildItemID][i] > 0)
        {
            new itemName[32];
            GetItemName(BuildingInfo[buildingid][buildItemID][i], itemName);
            
            format(string, sizeof(string), "%s%d. %s (x%d)\n", string, i+1, itemName, BuildingInfo[buildingid][buildItemAmount][i]);
        }
        else
        {
            format(string, sizeof(string), "%s%d. Empty\n", string, i+1);
        }
    }
    
    SetPVarInt(playerid, "StorageBuildingID", buildingid);
    ShowPlayerDialog(playerid, DIALOG_STYLE_LIST, "Storage Box", string, "Take", "Close");
    
    return 1;
}

ShowFurnaceMenu(playerid, buildingid)
{
    if(buildingid < 0 || buildingid >= BuildingCount) return 0;
    if(!IsValidDynamicObject(BuildingInfo[buildingid][buildObject])) return 0;
    
    new string[1024];
    format(string, sizeof(string), "Furnace:\n");
    
    // Check if furnace has fuel
    new bool:hasFuel = false;
    new fuelSlot = -1;
    
    for(new i = 0; i < 20; i++)
    {
        if(BuildingInfo[buildingid][buildItemID][i] == ITEM_WOOD || BuildingInfo[buildingid][buildItemID][i] == ITEM_CHARCOAL)
        {
            hasFuel = true;
            fuelSlot = i;
            break;
        }
    }
    
    if(hasFuel)
    {
        format(string, sizeof(string), "%sFurnace is active (has fuel)\n\n", string);
    }
    else
    {
        format(string, sizeof(string), "%sFurnace needs fuel to work\n\n", string);
    }
    
    // List contents
    for(new i = 0; i < 20; i++)
    {
        if(BuildingInfo[buildingid][buildItemID][i] > 0)
        {
            new itemName[32];
            GetItemName(BuildingInfo[buildingid][buildItemID][i], itemName);
            
            format(string, sizeof(string), "%s%d. %s (x%d)\n", string, i+1, itemName, BuildingInfo[buildingid][buildItemAmount][i]);
        }
        else
        {
            format(string, sizeof(string), "%s%d. Empty\n", string, i+1);
        }
    }
    
    SetPVarInt(playerid, "FurnaceBuildingID", buildingid);
    ShowPlayerDialog(playerid, DIALOG_STYLE_LIST, "Furnace", string, "Interact", "Close");
    
    return 1;
}

ShowCampfireMenu(playerid, buildingid)
{
    if(buildingid < 0 || buildingid >= BuildingCount) return 0;
    if(!IsValidDynamicObject(BuildingInfo[buildingid][buildObject])) return 0;
    
    new string[512];
    format(string, sizeof(string), "Campfire:\n");
    
    // Check if campfire has fuel
    new bool:hasFuel = false;
    
    for(new i = 0; i < 20; i++)
    {
        if(BuildingInfo[buildingid][buildItemID][i] == ITEM_WOOD)
        {
            hasFuel = true;
            break;
        }
    }
    
    if(hasFuel)
    {
        format(string, sizeof(string), "%sCampfire is active (has fuel)\n\n", string);
        format(string, sizeof(string), "%sActions:\n", string);
        format(string, sizeof(string), "%s1. Cook Food\n", string);
        format(string, sizeof(string), "%s2. View Contents\n", string);
        format(string, sizeof(string), "%s3. Add Fuel (Wood)\n", string);
    }
    else
    {
        format(string, sizeof(string), "%sCampfire needs fuel to work\n\n", string);
        format(string, sizeof(string), "%sActions:\n", string);
        format(string, sizeof(string), "%s1. Add Fuel (Wood)\n", string);
        format(string, sizeof(string), "%s2. View Contents\n", string);
    }
    
    SetPVarInt(playerid, "CampfireBuildingID", buildingid);
    ShowPlayerDialog(playerid, DIALOG_STYLE_LIST, "Campfire", string, "Select", "Close");
    
    return 1;
}

HitBuilding(playerid)
{
    // Find closest building
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    new buildingid = -1;
    new Float:minDist = 3.0;
    
    for(new i = 0; i < BuildingCount; i++)
    {
        if(!IsValidDynamicObject(BuildingInfo[i][buildObject])) continue;
        
        new Float:dist = GetDistanceBetweenPoints3D(x, y, z, BuildingInfo[i][buildX], BuildingInfo[i][buildY], BuildingInfo[i][buildZ]);
        if(dist < minDist)
        {
            minDist = dist;
            buildingid = i;
        }
    }
    
    if(buildingid == -1) return 0;
    
    // Calculate damage based on weapon
    new weaponid = GetPlayerWeapon(playerid);
    new damage = 0;
    
    switch(weaponid)
    {
        case 0: damage = 1; // Fist
        case 1: damage = 1; // Brass Knuckles
        case 2, 3, 4, 5, 6, 7, 8: damage = 2; // Melee weapons
        case 9: damage = 5; // Chainsaw
        case 22: damage = 5; // Pistol
        case 23: damage = 5; // Silenced Pistol
        case 24: damage = 7; // Desert Eagle
        case 25, 26, 27: damage = 10; // Shotguns
        case 28, 32: damage = 8; // Uzi/Tec9
        case 29, 30, 31: damage = 12; // MP5, AK47, M4
        case 33, 34: damage = 15; // Rifles
        case 35, 36, 37, 38: damage = 25; // Rockets/grenades
        default: damage = 3;
    }
    
    // Apply damage to building
    BuildingInfo[buildingid][buildHealth] -= damage;
    
    // Check if building is destroyed
    if(BuildingInfo[buildingid][buildHealth] <= 0)
    {
        // Create explosion effect
        CreateExplosion(BuildingInfo[buildingid][buildX], BuildingInfo[buildingid][buildY], BuildingInfo[buildingid][buildZ], 12, 1.0);
        
        // Drop items if storage
        if(BuildingInfo[buildingid][buildType] == 8)
        {
            DropBuildingItems(buildingid);
        }
        
        // Destroy building
        DestroyDynamicObject(BuildingInfo[buildingid][buildObject]);
        BuildingInfo[buildingid][buildObject] = INVALID_OBJECT_ID;
        
        // Remove from database
        new query[128];
        mysql_format(g_SQL, query, sizeof(query), "DELETE FROM buildings WHERE id = %d", BuildingInfo[buildingid][buildID]);
        mysql_tquery(g_SQL, query);
        
        // Also remove any items stored in it
        mysql_format(g_SQL, query, sizeof(query), "DELETE FROM building_items WHERE building_id = %d", BuildingInfo[buildingid][buildID]);
        mysql_tquery(g_SQL, query);
        
        // Send message
        SendClientMessage(playerid, COLOR_GREEN, "You destroyed a building!");
    }
    else
    {
        // Show damage effect
        new Float:health_percent = (float(BuildingInfo[buildingid][buildHealth]) / float(BuildingInfo[buildingid][buildMaxHealth])) * 100.0;
        
        if(health_percent < 25.0)
        {
            // Building critically damaged
            SendClientMessage(playerid, COLOR_RED, "This building is about to collapse!");
        }
        else if(health_percent < 50.0)
        {
            // Building badly damaged
            SendClientMessage(playerid, COLOR_ORANGE, "This building is heavily damaged!");
        }
    }
    
    return 1;
}

DropBuildingItems(buildingid)
{
    if(buildingid < 0 || buildingid >= BuildingCount) return 0;
    
    // Create loot container at building position
    new lootid = FindFreeLootContainer();
    if(lootid == -1) return 0;
    
    LootInfo[lootid][lootType] = 4; // Drop bag
    LootInfo[lootid][lootX] = BuildingInfo[buildingid][buildX];
    LootInfo[lootid][lootY] = BuildingInfo[buildingid][buildY];
    LootInfo[lootid][lootZ] = BuildingInfo[buildingid][buildZ];
    LootInfo[lootid][lootInterior] = 0;
    LootInfo[lootid][lootVW] = 0;
    LootInfo[lootid][lootActive] = true;
    LootInfo[lootid][lootRespawnTime] = 300; // 5 minutes
    
    // Transfer building items to loot container
    for(new i = 0; i < 10; i++)
    {
        LootInfo[lootid][lootItems][i] = 0;
        LootInfo[lootid][lootItemsAmount][i] = 0;
    }
    
    new itemCount = 0;
    
    for(new i = 0; i < 20 && itemCount < 10; i++)
    {
        if(BuildingInfo[buildingid][buildItemID][i] > 0)
        {
            LootInfo[lootid][lootItems][itemCount] = BuildingInfo[buildingid][buildItemID][i];
            LootInfo[lootid][lootItemsAmount][itemCount] = BuildingInfo[buildingid][buildItemAmount][i];
            itemCount++;
        }
    }
    
    // Create object for loot bag
    LootInfo[lootid][lootObject] = CreateDynamicObject(2969, 
        LootInfo[lootid][lootX], 
        LootInfo[lootid][lootY], 
        LootInfo[lootid][lootZ], 
        0.0, 0.0, 0.0, 0, 0);
        
    return 1;
}

LoadLootContainers()
{
    print("Spawning loot containers...");
    
    // Spawn barrels
    for(new i = 0; i < 100; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        CreateLootContainerAtPos(0, x, y, z);
    }
    
    // Spawn crates
    for(new i = 0; i < 50; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        CreateLootContainerAtPos(1, x, y, z);
    }
    
    // Spawn military crates (fewer, better loot)
    for(new i = 0; i < 25; i++)
    {
        new Float:x = -3000.0 + float(random(6000));
        new Float:y = -3000.0 + float(random(6000));
        new Float:z = 0.0;
        
        CreateLootContainerAtPos(2, x, y, z);
    }
    
    printf("Spawned %d loot containers", LootCount);
    
    return 1;
}

CreateLootContainerAtPos(type, Float:x, Float:y, Float:z)
{
    if(LootCount >= MAX_LOOT_CONTAINERS) return -1;
    
    LootInfo[LootCount][lootType] = type;
    LootInfo[LootCount][lootX] = x;
    LootInfo[LootCount][lootY] = y;
    LootInfo[LootCount][lootZ] = z;
    LootInfo[LootCount][lootInterior] = 0;
    LootInfo[LootCount][lootVW] = 0;
    LootInfo[LootCount][lootActive] = true;
    LootInfo[LootCount][lootRespawnTime] = 300 + random(300); // 5-10 minutes
    
    // Create object based on type
    switch(type)
    {
        case 0: // Barrel
        {
            LootInfo[LootCount][lootObject] = CreateDynamicObject(1225, x, y, z, 0.0, 0.0, 0.0, -1, -1, -1, 300.0);
        }
        case 1: // Crate
        {
            LootInfo[LootCount][lootObject] = CreateDynamicObject(964, x, y, z, 0.0, 0.0, 0.0, -1, -1, -1, 300.0);
        }
        case 2: // Military Crate
        {
            LootInfo[LootCount][lootObject] = CreateDynamicObject(2977, x, y, z, 0.0, 0.0, 0.0, -1, -1, -1, 300.0);
        }
        case 3: // Elite Crate
        {
            LootInfo[LootCount][lootObject] = CreateDynamicObject(3798, x, y, z, 0.0, 0.0, 0.0, -1, -1, -1, 300.0);
        }
    }
    
    // Fill with random loot
    for(new i = 0; i < 10; i++)
    {
        LootInfo[LootCount][lootItems][i] = 0;
        LootInfo[LootCount][lootItemsAmount][i] = 0;
    }
    
    new itemCount = random(5) + 1; // 1-5 items
    
    for(new i = 0; i < itemCount; i++)
    {
        new slot = i;
        new itemType;
        
        switch(type)
        {
            case 0: // Barrel - basic items
            {
                itemType = GetRandomBasicItem();
            }
            case 1: // Crate - medium tier items
            {
                itemType = GetRandomMediumItem();
            }
            case 2: // Military Crate - high tier items
            {
                itemType = GetRandomHighTierItem();
            }
            case 3: // Elite Crate - very high tier items
            {
                itemType = GetRandomEliteItem();
            }
        }
        
        new amount = 1;
        
        // Adjust amount for some items
        switch(itemType)
        {
            case ITEM_FOOD, ITEM_WATER, ITEM_BANDAGE:
                amount = 1 + random(3);
            case ITEM_AMMO_PISTOL, ITEM_AMMO_RIFLE, ITEM_AMMO_SHOTGUN:
                amount = 5 + random(15);
            case ITEM_METAL_FRAGMENTS, ITEM_GUNPOWDER, ITEM_SULFUR, ITEM_CHARCOAL:
                amount = 10 + random(40);
        }
        
        LootInfo[LootCount][lootItems][slot] = itemType;
        LootInfo[LootCount][lootItemsAmount][slot] = amount;
    }
    
    LootCount++;
    
    return LootCount - 1;
}

RespawnLootContainer(lootid)
{
    if(lootid < 0 || lootid >= LootCount) return 0;
    
    // Skip if it's a player drop
    if(LootInfo[lootid][lootType] == 4) return 0;
    
    // Recreate the object
    switch(LootInfo[lootid][lootType])
    {
        case 0: // Barrel
        {
            LootInfo[lootid][lootObject] = CreateDynamicObject(1225, 
                LootInfo[lootid][lootX], 
                LootInfo[lootid][lootY], 
                LootInfo[lootid][lootZ], 
                0.0, 0.0, 0.0, 
                LootInfo[lootid][lootVW], 
                LootInfo[lootid][lootInterior], 
                -1, 300.0);
        }
        case 1: // Crate
        {
            LootInfo[lootid][lootObject] = CreateDynamicObject(964, 
                LootInfo[lootid][lootX], 
                LootInfo[lootid][lootY], 
                LootInfo[lootid][lootZ], 
                0.0, 0.0, 0.0, 
                LootInfo[lootid][lootVW], 
                LootInfo[lootid][lootInterior], 
                -1, 300.0);
        }
        case 2: // Military Crate
        {
            LootInfo[lootid][lootObject] = CreateDynamicObject(2977, 
                LootInfo[lootid][lootX], 
                LootInfo[lootid][lootY], 
                LootInfo[lootid][lootZ], 
                0.0, 0.0, 0.0, 
                LootInfo[lootid][lootVW], 
                LootInfo[lootid][lootInterior], 
                -1, 300.0);
        }
        case 3: // Elite Crate
        {
            LootInfo[lootid][lootObject] = CreateDynamicObject(3798, 
                LootInfo[lootid][lootX], 
                LootInfo[lootid][lootY], 
                LootInfo[lootid][lootZ], 
                0.0, 0.0, 0.0, 
                LootInfo[lootid][lootVW], 
                LootInfo[lootid][lootInterior], 
                -1, 300.0);
        }
    }
    
    // Generate new loot
    for(new i = 0; i < 10; i++)
    {
        LootInfo[lootid][lootItems][i] = 0;
        LootInfo[lootid][lootItemsAmount][i] = 0;
    }
    
    new itemCount = random(5) + 1; // 1-5 items
    
    for(new i = 0; i < itemCount; i++)
    {
        new slot = i;
        new itemType;
        
        switch(LootInfo[lootid][lootType])
        {
            case 0: // Barrel - basic items
            {
                itemType = GetRandomBasicItem();
            }
            case 1: // Crate - medium tier items
            {
                itemType = GetRandomMediumItem();
            }
            case 2: // Military Crate - high tier items
            {
                itemType = GetRandomHighTierItem();
            }
            case 3: // Elite Crate - very high tier items
            {
                itemType = GetRandomEliteItem();
            }
        }
        
        new amount = 1;
        
        // Adjust amount for some items
        switch(itemType)
        {
            case ITEM_FOOD, ITEM_WATER, ITEM_BANDAGE:
                amount = 1 + random(3);
            case ITEM_AMMO_PISTOL, ITEM_AMMO_RIFLE, ITEM_AMMO_SHOTGUN:
                amount = 5 + random(15);
            case ITEM_METAL_FRAGMENTS, ITEM_GUNPOWDER, ITEM_SULFUR, ITEM_CHARCOAL:
                amount = 10 + random(40);
        }
        
        LootInfo[lootid][lootItems][slot] = itemType;
        LootInfo[lootid][lootItemsAmount][slot] = amount;
    }
    
    LootInfo[lootid][lootActive] = true;
    
    return 1;
}

FindFreeLootContainer()
{
    // First try to find an inactive container
    for(new i = 0; i < LootCount; i++)
    {
        if(!LootInfo[i][lootActive])
        {
            return i;
        }
    }
    
    // If none found, create a new one if there's space
    if(LootCount < MAX_LOOT_CONTAINERS)
    {
        return LootCount;
    }
    
    // No space, return invalid
    return -1;
}

CreateDeathLoot(playerid)
{
    // Get player position
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    // Create loot container
    new lootid = FindFreeLootContainer();
    if(lootid == -1) return 0;
    
    LootInfo[lootid][lootType] = 4; // Dead Body
    LootInfo[lootid][lootX] = x;
    LootInfo[lootid][lootY] = y;
    LootInfo[lootid][lootZ] = z;
    LootInfo[lootid][lootInterior] = GetPlayerInterior(playerid);
    LootInfo[lootid][lootVW] = GetPlayerVirtualWorld(playerid);
    LootInfo[lootid][lootActive] = true;
    LootInfo[lootid][lootRespawnTime] = 300; // 5 minutes
    
    // Transfer player's inventory to loot container
    for(new i = 0; i < 10; i++)
    {
        LootInfo[lootid][lootItems][i] = 0;
        LootInfo[lootid][lootItemsAmount][i] = 0;
    }
    
    new itemCount = 0;
    
    // Transfer resources
    for(new i = 0; i < 5; i++)
    {
        if(PlayerInfo[playerid][pMaterials][i] > 0 && itemCount < 10)
        {
            // Convert resource type to item ID
            new itemType;
            switch(i)
            {
                case 0: itemType = ITEM_WOOD;
                case 1: itemType = ITEM_STONE;
                case 2: itemType = ITEM_METAL;
                case 3: itemType = ITEM_CLOTH;
                case 4: itemType = ITEM_CRUDE_OIL;
            }
            
            LootInfo[lootid][lootItems][itemCount] = itemType;
            LootInfo[lootid][lootItemsAmount][itemCount] = PlayerInfo[playerid][pMaterials][i];
            itemCount++;
        }
    }
    
    // Transfer inventory items
    for(new i = 0; i < 30 && itemCount < 10; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] > 0)
        {
            LootInfo[lootid][lootItems][itemCount] = PlayerInfo[playerid][pInventory][i];
            LootInfo[lootid][lootItemsAmount][itemCount] = PlayerInfo[playerid][pInventoryAmount][i];
            itemCount++;
            
            if(itemCount >= 10) break; // Maximum 10 slots in loot container
        }
    }
    
    // Create death bag object
    LootInfo[lootid][lootObject] = CreateDynamicObject(2060, x, y, z - 0.5, 0.0, 0.0, 0.0, 
        LootInfo[lootid][lootVW], LootInfo[lootid][lootInterior]);
    
    return 1;
}

LoadSleepingPlayers()
{
    new query[128];
    mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM sleeping_players WHERE active = 1");
    mysql_tquery(g_SQL, query, "OnSleepingPlayersLoad", "");
    
    return 1;
}

forward OnSleepingPlayersLoad();
public OnSleepingPlayersLoad()
{
    new rows, fields;
    cache_get_row_count(rows);
    cache_get_field_count(fields);
    
    printf("Loading %d sleeping players...", rows);
    
    for(new i = 0; i < rows; i++)
    {
        if(i >= MAX_SLEEPING_PLAYERS) break;
        
        new sleepID = cache_get_field_content_int(i, "id");
        
        cache_get_field_content(i, "name", SleepingPlayers[i][sleepName], g_SQL, MAX_PLAYER_NAME);
        SleepingPlayers[i][sleepUserID] = cache_get_field_content_int(i, "user_id");
        SleepingPlayers[i][sleepX] = cache_get_field_content_float(i, "x");
        SleepingPlayers[i][sleepY] = cache_get_field_content_float(i, "y");
        SleepingPlayers[i][sleepZ] = cache_get_field_content_float(i, "z");
        SleepingPlayers[i][sleepRot] = cache_get_field_content_float(i, "rot");
        SleepingPlayers[i][sleepInterior] = cache_get_field_content_int(i, "interior");
        SleepingPlayers[i][sleepVW] = cache_get_field_content_int(i, "virtualworld");
        SleepingPlayers[i][sleepActive] = bool:cache_get_field_content_int(i, "active");
        SleepingPlayers[i][sleepHealth] = cache_get_field_content_float(i, "health");
        SleepingPlayers[i][sleepArmor] = cache_get_field_content_float(i, "armor");
        SleepingPlayers[i][sleepHunger] = cache_get_field_content_float(i, "hunger");
        SleepingPlayers[i][sleepThirst] = cache_get_field_content_float(i, "thirst");
        
        // Create sleeping player object
        SleepingPlayers[i][sleepObject] = CreateDynamicObject(1241, 
            SleepingPlayers[i][sleepX], 
            SleepingPlayers[i][sleepY], 
            SleepingPlayers[i][sleepZ], 
            0.0, 0.0, SleepingPlayers[i][sleepRot], 
            SleepingPlayers[i][sleepVW], 
            SleepingPlayers[i][sleepInterior]);
            
        // Load inventory and materials
        new query[128];
        mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM sleeping_inventory WHERE sleep_id = %d", sleepID);
        mysql_tquery(g_SQL, query, "OnSleepingInventoryLoad", "i", i);
        
        mysql_format(g_SQL, query, sizeof(query), "SELECT * FROM sleeping_materials WHERE sleep_id = %d", sleepID);
        mysql_tquery(g_SQL, query, "OnSleepingMaterialsLoad", "i", i);
        
        SleepingCount++;
    }
    
    printf("Loaded %d sleeping players", SleepingCount);
    
    return 1;
}

forward OnSleepingInventoryLoad(sleepindex);
public OnSleepingInventoryLoad(sleepindex)
{
    new rows, fields;
    cache_get_row_count(rows);
    cache_get_field_count(fields);
    
    // Clear inventory
    for(new i = 0; i < 30; i++)
    {
        SleepingPlayers[sleepindex][sleepInventory][i] = 0;
        SleepingPlayers[sleepindex][sleepInventoryAmount][i] = 0;
    }
    
    // Load items
    for(new i = 0; i < rows; i++)
    {
        new slot = cache_get_field_content_int(i, "slot");
        if(slot >= 0 && slot < 30)
        {
            SleepingPlayers[sleepindex][sleepInventory][slot] = cache_get_field_content_int(i, "item_id");
            SleepingPlayers[sleepindex][sleepInventoryAmount][slot] = cache_get_field_content_int(i, "amount");
        }
    }
    
    return 1;
}

forward OnSleepingMaterialsLoad(sleepindex);
public OnSleepingMaterialsLoad(sleepindex)
{
    new rows;
    cache_get_row_count(rows);
    
    if(rows > 0)
    {
        SleepingPlayers[sleepindex][sleepMaterials][0] = cache_get_field_content_int(0, "wood");
        SleepingPlayers[sleepindex][sleepMaterials][1] = cache_get_field_content_int(0, "stone");
        SleepingPlayers[sleepindex][sleepMaterials][2] = cache_get_field_content_int(0, "metal");
        SleepingPlayers[sleepindex][sleepMaterials][3] = cache_get_field_content_int(0, "cloth");
        SleepingPlayers[sleepindex][sleepMaterials][4] = cache_get_field_content_int(0, "fuel");
    }
    else
    {
        // Clear materials
        for(new i = 0; i < 5; i++)
        {
            SleepingPlayers[sleepindex][sleepMaterials][i] = 0;
        }
    }
    
    return 1;
}

public PlayerSleepSave(playerid)
{
    // Don't create sleeping player if health is too low
    if(PlayerInfo[playerid][pHealth] < 20.0) return 0;
    
    // Find free sleeping slot
    new sleepid = -1;
    
    for(new i = 0; i < MAX_SLEEPING_PLAYERS; i++)
    {
        if(!SleepingPlayers[i][sleepActive])
        {
            sleepid = i;
            break;
        }
    }
    
    if(sleepid == -1)
    {
        // No free slot
        return 0;
    }
    
    // Get player position
    new Float:x, Float:y, Float:z, Float:rot;
    GetPlayerPos(playerid, x, y, z);
    GetPlayerFacingAngle(playerid, rot);
    
    // Save sleeping player data
    GetPlayerName(playerid, SleepingPlayers[sleepid][sleepName], MAX_PLAYER_NAME);
    SleepingPlayers[sleepid][sleepUserID] = PlayerInfo[playerid][pID];
    SleepingPlayers[sleepid][sleepX] = x;
    SleepingPlayers[sleepid][sleepY] = y;
    SleepingPlayers[sleepid][sleepZ] = z;
    SleepingPlayers[sleepid][sleepRot] = rot;
    SleepingPlayers[sleepid][sleepInterior] = GetPlayerInterior(playerid);
    SleepingPlayers[sleepid][sleepVW] = GetPlayerVirtualWorld(playerid);
    SleepingPlayers[sleepid][sleepActive] = true;
    SleepingPlayers[sleepid][sleepHealth] = PlayerInfo[playerid][pHealth];
    SleepingPlayers[sleepid][sleepArmor] = PlayerInfo[playerid][pArmor];
    SleepingPlayers[sleepid][sleepHunger] = PlayerInfo[playerid][pHunger];
    SleepingPlayers[sleepid][sleepThirst] = PlayerInfo[playerid][pThirst];
    
    // Copy inventory
    for(new i = 0; i < 30; i++)
    {
        SleepingPlayers[sleepid][sleepInventory][i] = PlayerInfo[playerid][pInventory][i];
        SleepingPlayers[sleepid][sleepInventoryAmount][i] = PlayerInfo[playerid][pInventoryAmount][i];
    }
    
    // Copy materials
    for(new i = 0; i < 5; i++)
    {
        SleepingPlayers[sleepid][sleepMaterials][i] = PlayerInfo[playerid][pMaterials][i];
    }
    
    // Create sleeping player object
    SleepingPlayers[sleepid][sleepObject] = CreateDynamicObject(1241, x, y, z, 0.0, 0.0, rot, 
        SleepingPlayers[sleepid][sleepVW], SleepingPlayers[sleepid][sleepInterior]);
    
    // Save to database
    new query[512];
    mysql_format(g_SQL, query, sizeof(query), 
        "INSERT INTO sleeping_players (name, user_id, x, y, z, rot, interior, virtualworld, active, health, armor, hunger, thirst) VALUES ('%e', %d, %.4f, %.4f, %.4f, %.4f, %d, %d, 1, %.1f, %.1f, %.1f, %.1f)",
        SleepingPlayers[sleepid][sleepName],
        SleepingPlayers[sleepid][sleepUserID],
        SleepingPlayers[sleepid][sleepX],
        SleepingPlayers[sleepid][sleepY],
        SleepingPlayers[sleepid][sleepZ],
        SleepingPlayers[sleepid][sleepRot],
        SleepingPlayers[sleepid][sleepInterior],
        SleepingPlayers[sleepid][sleepVW],
        SleepingPlayers[sleepid][sleepHealth],
        SleepingPlayers[sleepid][sleepArmor],
        SleepingPlayers[sleepid][sleepHunger],
        SleepingPlayers[sleepid][sleepThirst]
    );
    mysql_tquery(g_SQL, query, "OnSleepingPlayerSave", "i", sleepid);
    
    SleepingCount++;
    
    return 1;
}

forward OnSleepingPlayerSave(sleepid);
public OnSleepingPlayerSave(sleepid)
{
    new sleepDBID = cache_insert_id();
    
    // Save inventory items
    new query[256];
    for(new i = 0; i < 30; i++)
    {
        if(SleepingPlayers[sleepid][sleepInventory][i] > 0)
        {
            mysql_format(g_SQL, query, sizeof(query), 
                "INSERT INTO sleeping_inventory (sleep_id, slot, item_id, amount) VALUES (%d, %d, %d, %d)",
                sleepDBID, i, SleepingPlayers[sleepid][sleepInventory][i], SleepingPlayers[sleepid][sleepInventoryAmount][i]
            );
            mysql_tquery(g_SQL, query);
        }
    }
    
    // Save materials
    mysql_format(g_SQL, query, sizeof(query), 
        "INSERT INTO sleeping_materials (sleep_id, wood, stone, metal, cloth, fuel) VALUES (%d, %d, %d, %d, %d, %d)",
        sleepDBID, 
        SleepingPlayers[sleepid][sleepMaterials][0],
        SleepingPlayers[sleepid][sleepMaterials][1],
        SleepingPlayers[sleepid][sleepMaterials][2],
        SleepingPlayers[sleepid][sleepMaterials][3],
        SleepingPlayers[sleepid][sleepMaterials][4]
    );
    mysql_tquery(g_SQL, query);
    
    return 1;
}

IsPlayerInSafeZone(playerid)
{
    // Check if player is in a safe zone
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
    // Safe zone coordinates - could be extended to a list
    if(GetDistanceBetweenPoints3D(x, y, z, 0.0, 0.0, 3.0) < 50.0) // Center of map is safe
    {
        return 1;
    }
    
    return 0;
}

// Helper functions
GetItemName(itemid, dest[], size = sizeof(dest))
{
    switch(itemid)
    {
        case ITEM_HATCHET: format(dest, size, "Hatchet");
        case ITEM_PICKAXE: format(dest, size, "Pickaxe");
        case ITEM_HAMMER: format(dest, size, "Hammer");
        case ITEM_FOOD: format(dest, size, "Food");
        case ITEM_WATER: format(dest, size, "Water");
        case ITEM_MEDKIT: format(dest, size, "Medkit");
        case ITEM_BANDAGE: format(dest, size, "Bandage");
        case ITEM_PISTOL: format(dest, size, "Pistol");
        case ITEM_RIFLE: format(dest, size, "Rifle");
        case ITEM_SHOTGUN: format(dest, size, "Shotgun");
        case ITEM_AMMO_PISTOL: format(dest, size, "Pistol Ammo");
        case ITEM_AMMO_RIFLE: format(dest, size, "Rifle Ammo");
        case ITEM_AMMO_SHOTGUN: format(dest, size, "Shotgun Ammo");
        case ITEM_RADIATION_SUIT: format(dest, size, "Radiation Suit");
        case ITEM_MAP: format(dest, size, "Map");
        case ITEM_SLEEPING_BAG: format(dest, size, "Sleeping Bag");
        case ITEM_FURNACE: format(dest, size, "Furnace");
        case ITEM_CAMPFIRE: format(dest, size, "Campfire");
        case ITEM_CODELOCK: format(dest, size, "Code Lock");
        case ITEM_KEYLOCK: format(dest, size, "Key Lock");
        case ITEM_KEY: format(dest, size, "Key");
        case ITEM_WOOD_DOOR: format(dest, size, "Wooden Door");
        case ITEM_METAL_DOOR: format(dest, size, "Metal Door");
        case ITEM_METAL_FRAGMENTS: format(dest, size, "Metal Fragments");
        case ITEM_CHARCOAL: format(dest, size, "Charcoal");
        case ITEM_GUNPOWDER: format(dest, size, "Gunpowder");
        case ITEM_EXPLOSIVE: format(dest, size, "Explosive");
        case ITEM_C4: format(dest, size, "C4");
        case ITEM_SULFUR: format(dest, size, "Sulfur");
        case ITEM_CRUDE_OIL: format(dest, size, "Crude Oil");
        case ITEM_WOOD: format(dest, size, "Wood");
        case ITEM_STONE: format(dest, size, "Stone");
        case ITEM_METAL: format(dest, size, "Metal");
        case ITEM_CLOTH: format(dest, size, "Cloth");
        default: format(dest, size, "Unknown Item");
    }
    return 1;
}

GetBuildingName(buildingType, dest[], size = sizeof(dest))
{
    switch(buildingType)
    {
        case 0: format(dest, size, "Foundation");
        case 1: format(dest, size, "Wall");
        case 2: format(dest, size, "Doorway");
        case 3: format(dest, size, "Door");
        case 4: format(dest, size, "Floor");
        case 5: format(dest, size, "Ceiling");
        case 6: format(dest, size, "Stairs");
        case 7: format(dest, size, "Window");
        case 8: format(dest, size, "Storage Box");
        case 16: format(dest, size, "Sleeping Bag");
        case 17: format(dest, size, "Furnace");
        case 18: format(dest, size, "Campfire");
        case 22: format(dest, size, "Wooden Door");
        case 23: format(dest, size, "Metal Door");
        default: format(dest, size, "Unknown Building");
    }
    return 1;
}

FindFreeInventorySlot(playerid, itemid)
{
    // First check if player already has this item in inventory
    for(new i = 0; i < 30; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] == itemid)
        {
            return i;
        }
    }
    
    // If not found, look for empty slot
    for(new i = 0; i < 30; i++)
    {
        if(PlayerInfo[playerid][pInventory][i] == 0)
        {
            return i;
        }
    }
    
    // No free slot
    return -1;
}

GetCraftingRequirements(itemType, &wood, &stone, &metal, &cloth, &other, &otherItem)
{
    wood = 0;
    stone = 0;
    metal = 0;
    cloth = 0;
    other = 0;
    otherItem = 0;
    
    switch(itemType)
    {
        case ITEM_HATCHET:
        {
            wood = 50;
            metal = 25;
        }
        case ITEM_PICKAXE:
        {
            wood = 50;
            metal = 40;
        }
        case ITEM_HAMMER:
        {
            wood = 100;
            metal = 50;
        }
        case ITEM_BANDAGE:
        {
            cloth = 10;
        }
        case ITEM_MEDKIT:
        {
            cloth = 50;
            metal = 20;
        }
        case ITEM_SLEEPING_BAG:
        {
            cloth = 100;
            wood = 30;
        }
        case ITEM_FURNACE:
        {
            stone = 500;
            wood = 100;
            metal = 50;
        }
        case ITEM_CAMPFIRE:
        {
            wood = 200;
            stone = 20;
        }
        case ITEM_WOOD_DOOR:
        {
            wood = 200;
            metal = 50;
        }
        case ITEM_METAL_DOOR:
        {
            metal = 300;
            wood = 50;
        }
        case ITEM_CODELOCK:
        {
            metal = 100;
        }
        case ITEM_PISTOL:
        {
            metal = 150;
            wood = 50;
            other = 20;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_SHOTGUN:
        {
            metal = 200;
            wood = 100;
            other = 30;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_RIFLE:
        {
            metal = 300;
            wood = 150;
            other = 50;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_AMMO_PISTOL:
        {
            metal = 20;
            other = 10;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_AMMO_SHOTGUN:
        {
            metal = 30;
            other = 15;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_AMMO_RIFLE:
        {
            metal = 40;
            other = 20;
            otherItem = ITEM_GUNPOWDER;
        }
        case ITEM_GUNPOWDER:
        {
            other = 30;
            otherItem = ITEM_CHARCOAL;
            stone = 20; // Representing sulfur as stone for simplicity
        }
        case ITEM_EXPLOSIVE:
        {
            other = 100;
            otherItem = ITEM_GUNPOWDER;
            metal = 50;
            cloth = 20;
        }
        case ITEM_C4:
        {
            other = 5;
            otherItem = ITEM_EXPLOSIVE;
            metal = 100;
            cloth = 60;
        }
    }
    
    return 1;
}

GetCraftingTime(itemType)
{
    switch(itemType)
    {
        case ITEM_HATCHET, ITEM_PICKAXE, ITEM_HAMMER: return 5; // Basic tools
        case ITEM_BANDAGE: return 3;
        case ITEM_MEDKIT: return 10;
        case ITEM_SLEEPING_BAG: return 5;
        case ITEM_FURNACE: return 15;
        case ITEM_CAMPFIRE: return 8;
        case ITEM_WOOD_DOOR: return 10;
        case ITEM_METAL_DOOR: return 15;
        case ITEM_CODELOCK: return 8;
        case ITEM_PISTOL: return 20;
        case ITEM_SHOTGUN: return 25;
        case ITEM_RIFLE: return 30;
        case ITEM_AMMO_PISTOL, ITEM_AMMO_SHOTGUN, ITEM_AMMO_RIFLE: return 8;
        case ITEM_GUNPOWDER: return 10;
        case ITEM_EXPLOSIVE: return 15;
        case ITEM_C4: return 30;
        default: return 5;
    }
}

GetBuildingRequirements(buildType, &wood, &stone, &metal)
{
    wood = 0;
    stone = 0;
    metal = 0;
    
    switch(buildType)
    {
        case 0: // Foundation
        {
            wood = 500;
            stone = 300;
        }
        case 1: // Wall
        {
            wood = 200;
            stone = 100;
        }
        case 2: // Doorway
        {
            wood = 180;
            stone = 90;
        }
        case 3: // Door
        {
            wood = 100;
            metal = 20;
        }
        case 4: // Floor
        {
            wood = 150;
            stone = 80;
        }
        case 5: // Ceiling
        {
            wood = 150;
            stone = 80;
        }
        case 6: // Stairs
        {
            wood = 250;
            stone = 150;
        }
        case 7: // Window
        {
            wood = 160;
            stone = 80;
        }
        case 8: // Storage Box
        {
            wood = 100;
            metal = 20;
        }
    }
    
    return 1;
}

GetRandomBasicItem()
{
    new items[10] = {
        ITEM_HATCHET, ITEM_PICKAXE, ITEM_FOOD, ITEM_WATER, ITEM_BANDAGE,
        ITEM_CLOTH, ITEM_WOOD, ITEM_STONE, ITEM_METAL, ITEM_CHARCOAL
    };
    
    return items[random(sizeof(items))];
}

GetRandomMediumItem()
{
    new items[12] = {
        ITEM_HATCHET, ITEM_PICKAXE, ITEM_HAMMER, ITEM_FOOD, ITEM_WATER,
        ITEM_BANDAGE, ITEM_MEDKIT, ITEM_SLEEPING_BAG, ITEM_KEYLOCK, 
        ITEM_METAL_FRAGMENTS, ITEM_GUNPOWDER, ITEM_AMMO_PISTOL
    };
    
    return items[random(sizeof(items))];
}

GetRandomHighTierItem()
{
    new items[10] = {
        ITEM_PISTOL, ITEM_SHOTGUN, ITEM_AMMO_PISTOL, ITEM_AMMO_SHOTGUN, 
        ITEM_MEDKIT, ITEM_CODELOCK, ITEM_GUNPOWDER, ITEM_EXPLOSIVE,
        ITEM_WOOD_DOOR, ITEM_METAL_DOOR
    };
    
    return items[random(sizeof(items))];
}

GetRandomEliteItem()
{
    new items[8] = {
        ITEM_RIFLE, ITEM_SHOTGUN, ITEM_AMMO_RIFLE, ITEM_RADIATION_SUIT, 
        ITEM_C4, ITEM_EXPLOSIVE, ITEM_METAL_DOOR, ITEM_FURNACE
    };
    
    return items[random(sizeof(items))];
}

FormatTimestamp(timestamp)
{
    new year, month, day, hour, minute, second;
    timestamp_to_date(timestamp, year, month, day, hour, minute, second);
    
    new result[32];
    format(result, sizeof(result), "%02d/%02d/%04d %02d:%02d", day, month, year, hour, minute);
    
    return result;
}

GetPlayerNameEx(playerid)
{
    new name[MAX_PLAYER_NAME];
    GetPlayerName(playerid, name, sizeof(name));
    return name;
}

// Time functions
timestamp_to_date(timestamp, &year, &month, &day, &hour, &minute, &second)
{
    new days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    new seconds_in_day = 86400; // 24 * 60 * 60
    new seconds_in_hour = 3600; // 60 * 60
    new seconds_in_minute = 60;
    
    // Base time: 1970-01-01 00:00:00 UTC
    year = 1970;
    month = 1;
    day = 1;
    
    // Calculate year
    while(true)
    {
        new days_in_year = 365;
        if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) // Leap year
            days_in_year = 366;
            
        new seconds_in_year = days_in_year * seconds_in_day;
        
        if(timestamp < seconds_in_year)
            break;
            
        timestamp -= seconds_in_year;
        year++;
    }
    
    // Update February days for leap year
    if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
        days_in_month[1] = 29;
    
    // Calculate month
    while(timestamp >= days_in_month[month-1] * seconds_in_day)
    {
        timestamp -= days_in_month[month-1] * seconds_in_day;
        month++;
    }
    
    // Calculate day
    day += timestamp / seconds_in_day;
    timestamp %= seconds_in_day;
    
    // Calculate hour, minute, second
    hour = timestamp / seconds_in_hour;
    timestamp %= seconds_in_hour;
    
    minute = timestamp / seconds_in_minute;
    second = timestamp % seconds_in_minute;
    
    return 1;
}

Этот полный код мода Rust для SA-MP имеет
Расширенную систему выживания с голодом, жаждой и радиацией
Полноценный инвентарь и систему крафта с различными предметами
Детальную систему строительства баз
Реалистичную систему рейдов с использованием С4 и взрывчатки
Систему спящих игроков, хранящую данные оффлайн-игроков
Продвинутую систему лута с контейнерами разного уровня
Функцию лутдропов для стимулирования PvP
Расширенную админ-панель для управления сервером
Полноценную MySQL базу данных для хранения всех игровых данных
Систему повреждений построек и их починки 
готовый к использованию на реальном сервере SA-MP. 
Требуется только настроить параметры подключения к MySQL базе данных и установить необходимые инклуды.
​​​
-- Таблица игроков
CREATE TABLE players (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(24) UNIQUE NOT NULL,
    password VARCHAR(65) NOT NULL,
    admin INT DEFAULT 0,
    kills INT DEFAULT 0,
    deaths INT DEFAULT 0,
    health FLOAT DEFAULT 100.0,
    armor FLOAT DEFAULT 0.0,
    hunger FLOAT DEFAULT 100.0,
    thirst FLOAT DEFAULT 100.0,
    radiation FLOAT DEFAULT 0.0,
    wood INT DEFAULT 0,
    stone INT DEFAULT 0,
    metal INT DEFAULT 0,
    cloth INT DEFAULT 0,
    fuel INT DEFAULT 0,
    lastX FLOAT DEFAULT 0.0,
    lastY FLOAT DEFAULT 0.0,
    lastZ FLOAT DEFAULT 0.0,
    interior INT DEFAULT 0,
    virtualworld INT DEFAULT 0,
    spawnpoint INT DEFAULT 0,
    hasmap INT DEFAULT 0,
    lastlogin INT DEFAULT 0,
    registerdate INT DEFAULT 0,
    playtime INT DEFAULT 0
);

-- Инвентарь игроков
CREATE TABLE inventory (
    player_id INT,
    slot INT,
    item_id INT,
    amount INT,
    PRIMARY KEY (player_id, slot),
    FOREIGN KEY (player_id) REFERENCES players(id) ON DELETE CASCADE
);

-- Постройки
CREATE TABLE buildings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    owner INT,
    type INT,
    x FLOAT,
    y FLOAT,
    z FLOAT,
    rx FLOAT,
    ry FLOAT,
    rz FLOAT,
    health INT,
    maxhealth INT,
    lockcode VARCHAR(10),
    locked INT DEFAULT 0,
    FOREIGN KEY (owner) REFERENCES players(id) ON DELETE SET NULL
);

-- Предметы в постройках
CREATE TABLE building_items (
    building_id INT,
    slot INT,
    item_id INT,
    amount INT,
    PRIMARY KEY (building_id, slot),
    FOREIGN KEY (building_id) REFERENCES buildings(id) ON DELETE CASCADE
);

-- Спящие игроки
CREATE TABLE sleeping_players (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(24),
    user_id INT,
    x FLOAT,
    y FLOAT,
    z FLOAT,
    rot FLOAT,
    interior INT,
    virtualworld INT,
    active INT DEFAULT 1,
    health FLOAT,
    armor FLOAT,
    hunger FLOAT,
    thirst FLOAT,
    FOREIGN KEY (user_id) REFERENCES players(id) ON DELETE CASCADE
);

-- Инвентарь спящих игроков
CREATE TABLE sleeping_inventory (
    sleep_id INT,
    slot INT,
    item_id INT,
    amount INT,
    PRIMARY KEY (sleep_id, slot),
    FOREIGN KEY (sleep_id) REFERENCES sleeping_players(id) ON DELETE CASCADE
);

-- Материалы спящих игроков
CREATE TABLE sleeping_materials (
    sleep_id INT PRIMARY KEY,
    wood INT DEFAULT 0,
    stone INT DEFAULT 0,
    metal INT DEFAULT 0,
    cloth INT DEFAULT 0,
    fuel INT DEFAULT 0,
    FOREIGN KEY (sleep_id) REFERENCES sleeping_players(id) ON DELETE CASCADE
);

Сообщение отредактировал pinople: 07 марта 2025 - 04:52

0

#2
Пользователь офлайн   MuthaX 

  • Эксперт
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияpinople (06 марта 2025 - 12:30) писал:

Нажмите сюда, чтобы прочитать это сообщение. [Показать]

А где плагин для работы с rust-бинарниками? И почему приведённый код написан на Pawn, а не на Rust?
0

#3
Пользователь офлайн   21th year 

  • Профессионал
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияMuthaX (06 марта 2025 - 15:55) писал:

А где плагин для работы с rust-бинарниками? И почему приведённый код написан на Pawn, а не на Rust?

Потому что в этом контексте, Rust это игра
0

#4
Пользователь офлайн   Romzes 

  • ( ^_^ )
  • Вставить ник
  • Раскрыть информацию
Моды лучше выкладывать файлом, чтобы люди могли скачать и запустить
0

#5
Пользователь офлайн   DeimoS 

  • Evil Scripter
  • Вставить ник
  • Раскрыть информацию
"Экспорт таблиц и баз данных в MySQL с возможностью лёгкого импорта" - *просто существует*
0

#6
Пользователь офлайн   TommyAtlanta 

  • Прохожий
  • Вставить ник
  • Раскрыть информацию
Больше походит на крупный розыгрыш от нейросети.

Отсутствуют многие фрагменты диалогов, макросы, синтаксические ошибки и ошибки в аргументах
мод больше огрызок чем база для старта

upd. В прочем хуже провести своё время и придумать нельзя
но пол дела было уже сделано как я понял что это ошибка

В общем от себя я собрал полностью архитектуру и переписал загрузку на R41 (мод был на R39)
вдруг у кого то будет желание с "этим" что-то сделать, так что живите в доволь и не парьтесь

Скачать

Изображение

Сообщение отредактировал TommyAtlanta: 07 марта 2025 - 05:33

0

#7
Пользователь офлайн   pinople 

  • Прохожий
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияTommyAtlanta (07 марта 2025 - 04:30) писал:

Нажмите сюда, чтобы прочитать это сообщение. [Показать]
1.0 [Показать]

0

#8
Пользователь офлайн   TommyAtlanta 

  • Прохожий
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияpinople (07 марта 2025 - 05:39) писал:

Нажмите сюда, чтобы прочитать это сообщение. [Показать]

Цитата

Ошибки в синтаксисе и аргументах можно исправь, а функционал доработать. это не финальный вариант, а отправная точка для улучшений

Это отправная точка в Зад.

Подобные темы разве что портят форумы и вводят в заблуждение юзеров
Какая проблема человеку интегрировать AI в своё IDE и сгенерировать похожее?

Ладно бы это ещё было доведено до ума и хотя-бы можно было запустить
а подобные мувы ни к чему, увы
0

#9
Пользователь офлайн   MuthaX 

  • Эксперт
  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияpinople (07 марта 2025 - 05:39) писал:

Эта версия мода 1.0 то есть самая первая, и конечно, в ней могут быть ошибки, пропущенные фрагменты и недоработки. Она создавалась как база для дальнейшего развития, а не как полностью завершённый продукт. Ошибки в синтаксисе и аргументах можно исправь, а функционал доработать. это не финальный вариант, а отправная точка для улучшений. я думаю этим всё сказано

Чел, если это не готовая к запуску версия, а полная недоработок, то, в лучшем случае, это не 1.x.x.x, а 0.0.x.x.

P.s: и да, лучше выкладывать ссылкой на какой-нибудь гитхаб, т.к. саму тему ты не отредачишь спустя продолжительное время.

Сообщение отредактировал MuthaX: 07 марта 2025 - 10:44

0

Поделиться темой:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей


Яндекс.Метрика