5180 fichiers 38.5 Mo 0 téléchargements 157 vues mis à jour il y a 4 heures ui
room-builder.js 25.7 Ko Télécharger le fichier
/**
 * Room Builder Plugin - Menu Costruzioni
 *
 * Plugin esterno per Nitro Client.
 * Richiede il RoomBuilderPlugin.jar lato server (Arcturus).
 *
 * Se rimuovi questo file, il bottone scompare automaticamente dalla UI.
 *
 * Colori e stili uniformati al tema Nitro Client.
 */
(function ()
{
    'use strict';

    // ─── Nitro Theme Colors ───
    var THEME = {
        // Card / Window
        headerBg:       '#1E7295',
        headerText:     '#FFFFFF',
        tabsBg:         '#185D79',
        cardBorder:     '#283F5D',
        contentBg:      '#DFDFDF',

        // Buttons
        btnPrimary:     '#3c6d82',
        btnPrimaryBrd:  '#1a617f',
        btnPrimaryHov:  '#4a8199',
        btnActive:      '#185D79',
        btnActiveBrd:   '#0f4a63',
        btnActiveHov:   '#1E7295',
        btnDanger:      '#a81a12',
        btnDangerBrd:   '#b9322a',
        btnDangerHov:   '#c43a32',
        btnSuccess:     '#00800b',
        btnSuccessBrd:  '#006d09',
        btnWarning:     '#ffc107',
        btnWarningBrd:  '#f3c12a',

        // Dark panel (infostand style)
        darkBg:         '#212131',
        darkBorder:     '#383853',
        darkShadow:     'inset 0 5px rgba(38,38,57,0.6), inset 0 -4px rgba(25,25,37,0.6)',

        // Grid items
        gridBg:         '#CDD3D9',
        gridBorder:     '#B6BEC5',
        gridActiveBg:   '#ECECEC',
        gridActiveBrd:  '#FFFFFF',

        // Text
        textLight:      '#FFFFFF',
        textDark:       '#212529',
        textMuted:      '#B6BEC5',

        // Typography
        fontFamily:     'Ubuntu, sans-serif',
        fontSm:         '0.7875rem',
        fontBase:       '0.9rem',

        // Misc
        borderRadius:   '0.5rem',
        borderRadiusSm: '0.25rem',
        scrollThumb:    'rgba(30, 114, 149, 0.4)',
        scrollThumbHov: 'rgba(30, 114, 149, 0.8)'
    };

    function waitForApi(callback, maxRetries)
    {
        if (maxRetries === undefined) maxRetries = 50;
        if (window.NitroPlugins)
        {
            callback(window.NitroPlugins);
            return;
        }
        if (maxRetries <= 0)
        {
            console.warn('[RoomBuilder] NitroPlugins API not found after retries');
            return;
        }
        setTimeout(function () { waitForApi(callback, maxRetries - 1); }, 200);
    }

    // ─── Constants ───
    var FLOOR = 10;
    var WALL = 20;

    // ─── Send chat command to server via proper API ───
    function sendCommand(api, command)
    {
        try
        {
            api.sendChat(':' + command);
        }
        catch (e)
        {
            console.warn('[RoomBuilder] sendCommand error:', e);
        }
    }

    // ─── Section Label Helper ───
    function createSectionLabel(container, text)
    {
        var label = document.createElement('div');
        label.textContent = text;
        label.style.cssText = 'font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontSm + ';font-weight:bold;color:' + THEME.textDark + ';margin:10px 0 6px 0;padding-bottom:4px;border-bottom:1px solid ' + THEME.gridBorder + ';text-transform:uppercase;letter-spacing:0.5px';
        container.appendChild(label);
    }

    // ─── Slider Helper ───
    function createSlider(container, label, min, max, value, step, onChange)
    {
        var row = document.createElement('div');
        row.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:6px;padding:4px 6px;background:' + THEME.gridBg + ';border:1px solid ' + THEME.gridBorder + ';border-radius:' + THEME.borderRadiusSm;

        var lbl = document.createElement('span');
        lbl.textContent = label;
        lbl.style.cssText = 'width:70px;color:' + THEME.textDark + ';font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontSm + ';font-weight:bold;flex-shrink:0';

        var slider = document.createElement('input');
        slider.type = 'range';
        slider.min = min;
        slider.max = max;
        slider.step = step || 1;
        slider.value = value;
        slider.style.cssText = 'flex:1;height:6px;cursor:pointer;accent-color:' + THEME.headerBg;

        var valDisplay = document.createElement('span');
        valDisplay.textContent = value;
        valDisplay.style.cssText = 'width:28px;color:' + THEME.textDark + ';font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontSm + ';text-align:center;font-weight:bold';

        var saveBtn = document.createElement('button');
        saveBtn.innerHTML = '&#x1F4BE;';
        saveBtn.title = 'Salva';
        saveBtn.style.cssText = 'width:28px;height:28px;min-height:28px;display:flex;align-items:center;justify-content:center;background:' + THEME.btnSuccess + ';border:2px solid ' + THEME.btnSuccessBrd + ';border-radius:' + THEME.borderRadius + ';cursor:pointer;font-size:11px;color:' + THEME.textLight;

        var resetBtn = document.createElement('button');
        resetBtn.innerHTML = '&#x21A9;';
        resetBtn.title = 'Ripristina';
        resetBtn.style.cssText = 'width:28px;height:28px;min-height:28px;display:flex;align-items:center;justify-content:center;background:' + THEME.btnDanger + ';border:2px solid ' + THEME.btnDangerBrd + ';border-radius:' + THEME.borderRadius + ';color:' + THEME.textLight + ';cursor:pointer;font-size:13px;font-weight:bold';

        slider.addEventListener('input', function ()
        {
            valDisplay.textContent = slider.value;
        });

        saveBtn.addEventListener('click', function ()
        {
            if (onChange) onChange(Number(slider.value));
        });

        resetBtn.addEventListener('click', function ()
        {
            slider.value = value;
            valDisplay.textContent = value;
            if (onChange) onChange(Number(value));
        });

        row.appendChild(lbl);
        row.appendChild(slider);
        row.appendChild(valDisplay);
        row.appendChild(saveBtn);
        row.appendChild(resetBtn);
        container.appendChild(row);

        return { slider: slider, valDisplay: valDisplay };
    }

    // ─── Button Helper ───
    function createButton(container, label, onClick, opts)
    {
        opts = opts || {};
        var isActive = opts.active || false;
        var isDanger = opts.danger || false;

        var bgColor = isDanger ? THEME.btnDanger : (isActive ? THEME.btnActive : THEME.btnPrimary);
        var borderColor = isDanger ? THEME.btnDangerBrd : (isActive ? THEME.btnActiveBrd : THEME.btnPrimaryBrd);
        var hoverColor = isDanger ? THEME.btnDangerHov : (isActive ? THEME.btnActiveHov : THEME.btnPrimaryHov);

        var btn = document.createElement('button');
        btn.textContent = label;
        btn.style.cssText = 'padding:0.25rem 0.5rem;border-radius:' + THEME.borderRadius + ';color:' + THEME.textLight + ';font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontSm + ';font-weight:500;cursor:pointer;border:2px solid ' + borderColor + ';transition:background .15s;background:' + bgColor + ';min-height:28px;box-shadow:none;' + (opts.fullWidth ? 'width:100%;' : '') + (opts.extraStyle || '');

        btn.addEventListener('mouseenter', function () { btn.style.background = hoverColor; });
        btn.addEventListener('mouseleave', function () { btn.style.background = bgColor; });
        btn.addEventListener('click', function ()
        {
            if (onClick) onClick(btn);
        });
        if (container) container.appendChild(btn);
        return btn;
    }

    // ─── Grid Row Helper ───
    function createButtonRow(container, cols, buttons)
    {
        var row = document.createElement('div');
        row.style.cssText = 'display:grid;grid-template-columns:repeat(' + cols + ',1fr);gap:6px;margin-bottom:6px';
        buttons.forEach(function (b) { createButton(row, b.label, b.onClick, b); });
        container.appendChild(row);
    }

    // ─── Utility: iterate room floor objects ───
    function forEachFloorObject(api, callback)
    {
        var session = api.getRoomSession();
        var engine = api.getRoomEngine();
        if (!session || !engine) return;
        var objects = engine.getRoomObjects(session.roomId, FLOOR);
        for (var i = 0; i < objects.length; i++)
        {
            var obj = engine.getRoomObject(session.roomId, objects[i].id, FLOOR);
            if (obj) callback(obj, objects[i].id, session.roomId, engine);
        }
    }

    // ─── State ───
    var state = {
        hidePyramids: false,
        hideCarpets: false,
        hideWalls: false,
        hideWired: false,
        frozen: false,
        teleporting: false
    };

    // ─── Stack clipboard (client-side memory) ───
    var stackClipboard = null;

    // ─── Plugin Init ───
    waitForApi(function (api)
    {
        api.register({
            name: 'room-builder',
            label: 'Menu costruzioni',
            icon: 'icon-cog',

            onOpen: function ()
            {
                var content = api.createWindow('room-builder', 'Menu costruzioni', 440);
                if (!content) return;

                // Apply Nitro content area style to the content container
                content.style.cssText = 'padding:10px;font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontBase;

                // ─── Warning banner (Nitro tabs style) ───
                var banner = document.createElement('div');
                banner.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:6px;background:' + THEME.tabsBg + ';border:1px solid ' + THEME.cardBorder + ';border-radius:' + THEME.borderRadiusSm + ';padding:8px 12px;margin-bottom:12px';
                banner.innerHTML = '<span style="font-size:16px">&#x26A0;</span><span style="color:' + THEME.textLight + ';font-family:' + THEME.fontFamily + ';font-size:' + THEME.fontSm + '">Assicurati di non spammare per non essere <b>mutato</b></span><span style="font-size:16px">&#x26A0;</span>';
                content.appendChild(banner);

                // ─── Sliders Section ───
                createSectionLabel(content, 'Controlli');

                var slidersDiv = document.createElement('div');
                slidersDiv.style.marginBottom = '8px';

                createSlider(slidersDiv, 'Altezza', -10, 40, 0, 1, function (val)
                {
                    try
                    {
                        sendCommand(api, 'autotile ' + val);
                    }
                    catch (e) { console.warn('[RoomBuilder] Height:', e); }
                });

                createSlider(slidersDiv, 'Velocita', 0, 10, 4, 1, function (val)
                {
                    sendCommand(api, 'rb_speed ' + val);
                });

                content.appendChild(slidersDiv);

                // ─── Screenshot ───
                var ssDiv = document.createElement('div');
                ssDiv.style.marginBottom = '8px';
                createButton(ssDiv, 'Fai lo screenshot della stanza', function ()
                {
                    api.takeScreenshot();
                }, { fullWidth: true, extraStyle: 'padding:6px 12px;' });
                content.appendChild(ssDiv);

                // ─── Avatar Section ───
                createSectionLabel(content, 'Avatar');

                createButtonRow(content, 2, [
                    {
                        label: state.frozen ? '\u2713 Avatar bloccato' : 'Blocca avatar',
                        active: state.frozen,
                        onClick: function (btn)
                        {
                            state.frozen = !state.frozen;
                            btn.textContent = state.frozen ? '\u2713 Avatar bloccato' : 'Blocca avatar';
                            btn.style.background = state.frozen ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.frozen ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            sendCommand(api, 'blocca');
                        }
                    },
                    {
                        label: state.teleporting ? '\u2713 Teletrasporto ON' : 'Teletrasporto',
                        active: state.teleporting,
                        onClick: function (btn)
                        {
                            state.teleporting = !state.teleporting;
                            btn.textContent = state.teleporting ? '\u2713 Teletrasporto ON' : 'Teletrasporto';
                            btn.style.background = state.teleporting ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.teleporting ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            sendCommand(api, 'rb_teleport');
                        }
                    }
                ]);

                // ─── Visibility Section ───
                createSectionLabel(content, 'Visibilita');

                createButtonRow(content, 3, [
                    {
                        label: state.hidePyramids ? 'Mostra piramidi' : 'Nascondi piramidi',
                        active: state.hidePyramids,
                        onClick: function (btn)
                        {
                            state.hidePyramids = !state.hidePyramids;
                            btn.style.background = state.hidePyramids ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.hidePyramids ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            btn.textContent = state.hidePyramids ? 'Mostra piramidi' : 'Nascondi piramidi';
                            try
                            {
                                forEachFloorObject(api, function (obj, objId, roomId, engine)
                                {
                                    if (obj.type && obj.type.toLowerCase().indexOf('pyramid') >= 0)
                                    {
                                        engine.changeObjectModelData(roomId, objId, FLOOR, 'furniture_alpha_multiplier', state.hidePyramids ? 0 : 1);
                                    }
                                });
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    },
                    {
                        label: state.hideCarpets ? 'Mostra tappeti' : 'Nascondi tappeti',
                        active: state.hideCarpets,
                        onClick: function (btn)
                        {
                            state.hideCarpets = !state.hideCarpets;
                            btn.style.background = state.hideCarpets ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.hideCarpets ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            btn.textContent = state.hideCarpets ? 'Mostra tappeti' : 'Nascondi tappeti';
                            try
                            {
                                forEachFloorObject(api, function (obj, objId, roomId, engine)
                                {
                                    if (obj.model)
                                    {
                                        var sizeZ = obj.model.getValue('furniture_size_z');
                                        if (sizeZ !== undefined && sizeZ <= 0.01)
                                        {
                                            engine.changeObjectModelData(roomId, objId, FLOOR, 'furniture_alpha_multiplier', state.hideCarpets ? 0 : 1);
                                        }
                                    }
                                });
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    },
                    {
                        label: state.hideWalls ? 'Mostra mura' : 'Nascondi mura',
                        active: state.hideWalls,
                        onClick: function (btn)
                        {
                            state.hideWalls = !state.hideWalls;
                            btn.style.background = state.hideWalls ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.hideWalls ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            btn.textContent = state.hideWalls ? 'Mostra mura' : 'Nascondi mura';
                            try
                            {
                                var session = api.getRoomSession();
                                var engine = api.getRoomEngine();
                                if (!session || !engine) return;
                                var objects = engine.getRoomObjects(session.roomId, WALL);
                                for (var i = 0; i < objects.length; i++)
                                {
                                    engine.changeObjectModelData(session.roomId, objects[i].id, WALL, 'furniture_alpha_multiplier', state.hideWalls ? 0 : 1);
                                }
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    }
                ]);

                // ─── Stack Section ───
                createSectionLabel(content, 'Pila (Stack)');

                createButtonRow(content, 4, [
                    {
                        label: 'Annulla pila',
                        onClick: function ()
                        {
                            sendCommand(api, 'autotile');
                        }
                    },
                    {
                        label: 'Seleziona pila',
                        onClick: function ()
                        {
                            try
                            {
                                var session = api.getRoomSession();
                                var engine = api.getRoomEngine();
                                if (!session || !engine) return;
                                var objects = engine.getRoomObjects(session.roomId, FLOOR);
                                stackClipboard = [];
                                for (var i = 0; i < objects.length; i++)
                                {
                                    var obj = engine.getRoomObject(session.roomId, objects[i].id, FLOOR);
                                    if (obj && obj.location)
                                    {
                                        stackClipboard.push({
                                            id: objects[i].id,
                                            x: Math.floor(obj.location.x),
                                            y: Math.floor(obj.location.y),
                                            z: obj.location.z,
                                            dir: obj.direction ? obj.direction.x : 0
                                        });
                                    }
                                }
                                console.log('[RoomBuilder] Pila selezionata: ' + stackClipboard.length + ' oggetti');
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    },
                    {
                        label: 'Copia pila',
                        onClick: function ()
                        {
                            if (!stackClipboard || stackClipboard.length === 0)
                            {
                                console.log('[RoomBuilder] Nessuna pila selezionata');
                                return;
                            }
                            console.log('[RoomBuilder] Pila copiata: ' + stackClipboard.length + ' oggetti');
                        }
                    },
                    {
                        label: 'Posiziona pila',
                        onClick: function ()
                        {
                            if (!stackClipboard || stackClipboard.length === 0)
                            {
                                console.log('[RoomBuilder] Nessuna pila da posizionare');
                                return;
                            }
                            try
                            {
                                for (var i = 0; i < stackClipboard.length; i++)
                                {
                                    var item = stackClipboard[i];
                                    api.sendStackHeight(item.id, Math.round(item.z * 100));
                                }
                                console.log('[RoomBuilder] Pila posizionata: ' + stackClipboard.length + ' oggetti');
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    }
                ]);

                // ─── Room Management Section ───
                createSectionLabel(content, 'Gestione stanza');

                createButtonRow(content, 3, [
                    {
                        label: 'Impostazioni',
                        onClick: function () { api.createLinkEvent('navigator/toggle-room-info'); }
                    },
                    {
                        label: 'Reload stanza',
                        onClick: function ()
                        {
                            try
                            {
                                var session = api.getRoomSession();
                                if (session) api.createLinkEvent('navigator/goto/' + session.roomId);
                            }
                            catch (e) { }
                        }
                    },
                    {
                        label: 'Unload stanza',
                        onClick: function ()
                        {
                            api.visitDesktop();
                        }
                    }
                ]);

                // ─── Floor Tools Section ───
                createSectionLabel(content, 'Strumenti pavimento');

                createButtonRow(content, 4, [
                    {
                        label: 'Max Tile',
                        onClick: function ()
                        {
                            sendCommand(api, 'maxtile');
                        }
                    },
                    {
                        label: 'Auto Tile',
                        onClick: function ()
                        {
                            sendCommand(api, 'autotile');
                        }
                    },
                    {
                        label: 'No Item Floor',
                        danger: true,
                        onClick: function ()
                        {
                            if (confirm('Sei sicuro? Tutti i furni verranno rimossi dal pavimento!'))
                            {
                                sendCommand(api, 'noitemfloor');
                            }
                        }
                    },
                    {
                        label: 'Edit Floorplan',
                        onClick: function () { api.createLinkEvent('floor-editor/toggle'); }
                    }
                ]);

                // ─── Wired Section ───
                createSectionLabel(content, 'Wired');

                createButtonRow(content, 2, [
                    {
                        label: state.hideWired ? 'Mostra wired' : 'Nascondi wired',
                        active: state.hideWired,
                        onClick: function (btn)
                        {
                            state.hideWired = !state.hideWired;
                            btn.style.background = state.hideWired ? THEME.btnActive : THEME.btnPrimary;
                            btn.style.borderColor = state.hideWired ? THEME.btnActiveBrd : THEME.btnPrimaryBrd;
                            btn.textContent = state.hideWired ? 'Mostra wired' : 'Nascondi wired';
                            try
                            {
                                forEachFloorObject(api, function (obj, objId, roomId, engine)
                                {
                                    if (obj.type && (obj.type.toLowerCase().indexOf('wf_') >= 0 || obj.type.toLowerCase().indexOf('wired') >= 0))
                                    {
                                        engine.changeObjectModelData(roomId, objId, FLOOR, 'furniture_alpha_multiplier', state.hideWired ? 0 : 1);
                                    }
                                });
                            }
                            catch (e) { console.warn('[RoomBuilder]', e); }
                        }
                    },
                    {
                        label: 'Prendi tutti gli wired',
                        danger: true,
                        onClick: function ()
                        {
                            sendCommand(api, 'pickwired');
                        }
                    }
                ]);

                // ─── Spacer ───
                var spacer = document.createElement('div');
                spacer.style.cssText = 'height:1px;background:' + THEME.gridBorder + ';margin:10px 0';
                content.appendChild(spacer);

                // ─── Back button (danger style like close button) ───
                var backDiv = document.createElement('div');
                createButton(backDiv, 'Torna indietro', function ()
                {
                    api.destroyWindow('room-builder');
                }, { fullWidth: true, danger: true, extraStyle: 'padding:6px 12px;' });
                content.appendChild(backDiv);
            },

            onClose: function ()
            {
                if (window.NitroPlugins) window.NitroPlugins.destroyWindow('room-builder');
            }
        });

        console.log('[NitroPlugins] Room Builder plugin loaded (Nitro theme)');
    });
})();
15Sujets
1Dépôts
20Membres
7En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser