View difference between Paste ID: BUyjt5Ua and GwmGxjwy
SHOW: | | - or go back to the newest paste.
1
-- LemonOS: Pocket Shell for Lemonphone
2
-- by ChatGPT (GPT-5)
3
-- Features: Persistent settings, live clock, distance-based signal bars, auto-netchat install
4
5
-- ===== CONFIG PATHS =====
6
local CONFIG_PATH = "/lemonos.cfg"
7
local NETCHAT_PATH = "/netchat"
8
local STARTUP_PATH = "/startup.lua"
9
10
-- ===== FIRMWARE INFO =====
11
local firmware = {
12
    device = "Lemonphone",
13
    version = "LemonOS 2.0"
14
}
15
16
-- ===== SETTINGS =====
17
local config = {
18
    username = "User",
19
    accentColor = colors.yellow,
20
    bgColor = colors.black,
21
    rednetSide = "back"
22
}
23
24
-- ===== CONFIG LOAD/SAVE =====
25
local function saveConfig()
26
    local file = fs.open(CONFIG_PATH, "w")
27
    if file then
28
        file.write(textutils.serialize(config))
29
        file.close()
30
    end
31
end
32
33
local function loadConfig()
34
    if fs.exists(CONFIG_PATH) then
35
        local file = fs.open(CONFIG_PATH, "r")
36
        if file then
37
            local data = file.readAll()
38
            file.close()
39
            local ok, tbl = pcall(textutils.unserialize, data)
40
            if ok and type(tbl) == "table" then
41
                for k, v in pairs(tbl) do config[k] = v end
42
            end
43
        end
44
    end
45
end
46
loadConfig()
47
48
-- ===== AUTO-DOWNLOAD NETCHAT =====
49
if not fs.exists(NETCHAT_PATH) then
50
    print("Downloading netchat...")
51
    if http then
52
        local ok, resp = pcall(http.get, "https://pastebin.com/raw/KeRK2UWE")
53
        if ok and resp then
54
            local content = resp.readAll()
55
            resp.close()
56
            local file = fs.open(NETCHAT_PATH, "w")
57
            file.write(content)
58
            file.close()
59
            print("netchat installed!")
60
        else
61
            print("Failed to download netchat.")
62
        end
63
    else
64
        print("HTTP API not enabled.")
65
    end
66
    -- set startup to run firm.lpsw
67
    local file = fs.open(STARTUP_PATH, "w")
68
    file.write('shell.run("firm.lpsw")')
69
    file.close()
70
end
71
72
-- ===== INITIALIZE REDNET =====
73
if peripheral.find("modem") then
74
    rednet.open(config.rednetSide)
75
else
76
    rednet.close(config.rednetSide)
77
end
78
79
-- ===== GLOBAL SIGNAL VARIABLE =====
80
local signalStrength = 0 -- 1–3 bars
81
82
-- ===== UTILITIES =====
83
local function centerText(y, text, color)
84
    local w = term.getSize()
85
    local x = math.floor((w - #text) / 2)
86
    term.setCursorPos(x, y)
87
    if color then term.setTextColor(color) end
88
    term.write(text)
89
    term.setTextColor(colors.white)
90
end
91
92
-- Map distance to signal bars
93
local function distanceToBars(distance)
94
    if distance <= 5 then
95
        return 3
96
    elseif distance <= 20 then
97
        return 2
98
    else
99
        return 1
100
    end
101
end
102
103
-- ===== ASYNC SIGNAL UPDATER =====
104
local function updateSignal()
105
    while true do
106
        local strength = 0
107
        if rednet.isOpen(config.rednetSide) then
108
            local peers = {}
109
            local ids = rednet.lookup("lemonphone_ping") or {}
110
            for _, id in ipairs(ids) do
111
                local ok = pcall(rednet.send, id, "ping", 0.1)
112
                if ok then
113
                    local d = math.abs(os.getComputerID() - id) -- simple heuristic for distance
114
                    table.insert(peers, d)
115
                end
116
            end
117
            if #peers > 0 then
118
                table.sort(peers)
119
                strength = distanceToBars(peers[1])
120
            end
121
        end
122
        signalStrength = strength
123
        sleep(5)
124
    end
125
end
126
127
-- Draw signal bars based on latest value
128
local function drawSignalBars()
129
    local barChar = "|"
130
    local maxBars = 3
131
    for i = 1, maxBars do
132
        if i <= signalStrength then
133
            term.setTextColor(colors.lime)
134
        else
135
            term.setTextColor(colors.gray)
136
        end
137
        term.write(barChar)
138
    end
139
    term.setTextColor(colors.white)
140
end
141
142
-- ===== TOP BAR =====
143
local function drawTopBar()
144
    local w = term.getSize()
145
    term.setCursorPos(1,1)
146
    term.setBackgroundColor(config.accentColor)
147
    term.clearLine()
148
149
    -- Left: signal
150
    term.setCursorPos(2,1)
151
    if rednet.isOpen(config.rednetSide) then
152
        drawSignalBars()
153
        term.write(" Net")
154
    else
155
        term.setTextColor(colors.red)
156
        term.write("X NoNet")
157
        term.setTextColor(colors.black)
158
    end
159
160
    -- Right: time/date
161
    local timeStr = textutils.formatTime(os.time(), true)
162
    local dateStr = os.date("%b %d")
163
    local clock = timeStr .. " | " .. dateStr
164
    term.setCursorPos(w - #clock - 1, 1)
165
    term.setTextColor(colors.black)
166
    term.write(clock)
167
end
168
169
-- ===== MENU =====
170
local function drawMenu(selected)
171
    local apps = {
172
        {name="Messages", cmd="netchat"},
173
        {name="Worm", cmd="worm"},
174
        {name="Falling Blocks", cmd="falling"},
175
		{name="Redirection", cmd="redirection"},
176
        {name="Settings", cmd="settings"},
177
        {name="About Lemonphone", cmd="about"},
178
        {name="Shutdown", cmd="shutdown"}
179
    }
180
181
    local startY = 4
182
    term.setTextColor(colors.white)
183
    for i, app in ipairs(apps) do
184
        term.setCursorPos(4, startY + i - 1)
185
        if i == selected then
186
            term.setBackgroundColor(colors.gray)
187
            term.setTextColor(colors.black)
188
        else
189
            term.setBackgroundColor(config.bgColor)
190
            term.setTextColor(colors.white)
191
        end
192
        term.clearLine()
193
        term.setCursorPos(4, startY + i - 1)
194
        term.write(app.name)
195
    end
196
197
    term.setBackgroundColor(config.bgColor)
198
    return apps
199
end
200
201
-- ===== SETTINGS MENU =====
202
local function openSettings()
203
    while true do
204
        term.setBackgroundColor(config.bgColor)
205
        term.clear()
206
        centerText(3, "Settings", config.accentColor)
207
        term.setCursorPos(2,5)
208
        term.write("1. Change Username")
209
        term.setCursorPos(2,6)
210
        term.write("2. Change Accent Color")
211
        term.setCursorPos(2,7)
212
        term.write("3. Back")
213
214
        local _, key = os.pullEvent("key")
215
        if key == keys.one then
216
            term.setCursorPos(2,9)
217
            term.clearLine()
218
            term.write("Enter new username: ")
219
            config.username = read()
220
            saveConfig()
221
        elseif key == keys.two then
222
            term.setCursorPos(2,9)
223
            term.clearLine()
224
            term.write("Color name (e.g. yellow): ")
225
            local colorName = read()
226
            if colors[colorName] then
227
                config.accentColor = colors[colorName]
228
                saveConfig()
229
            else
230
                term.setCursorPos(2,10)
231
                term.write("Invalid color.")
232
                sleep(1)
233
            end
234
        elseif key == keys.three then
235
            return
236
        end
237
    end
238
end
239
240
-- ===== ABOUT PAGE =====
241
local function aboutLemonphone()
242
    term.setBackgroundColor(config.bgColor)
243
    term.clear()
244
    centerText(3,"About Lemonphone", config.accentColor)
245
    term.setCursorPos(2,5)
246
    term.write("Device: " .. firmware.device)
247
    term.setCursorPos(2,6)
248
    term.write("Firmware: " .. firmware.version)
249
    term.setCursorPos(2,8)
250
    term.write("Press any key to return...")
251
    os.pullEvent("key")
252
end
253
254
-- ===== MAIN LOOP =====
255
local function mainLoop()
256
    local selected = 1
257
    local refreshRate = 1.0
258
    local timer = os.startTimer(refreshRate)
259
260
    while true do
261
        term.setBackgroundColor(config.bgColor)
262
        term.clear()
263
        drawTopBar()
264
        centerText(3, config.username .. "'s Lemonphone", config.accentColor)
265
        local apps = drawMenu(selected)
266
267
        local event, key = os.pullEvent()
268
        if event == "key" then
269
            if key == keys.up then selected = math.max(1, selected-1)
270
            elseif key == keys.down then selected = math.min(#apps, selected+1)
271
            elseif key == keys.enter then
272
                local chosen = apps[selected]
273
                if chosen.name == "Settings" then openSettings()
274
                elseif chosen.name == "About Lemonphone" then aboutLemonphone()
275
                else
276
                    term.setBackgroundColor(config.bgColor)
277
                    term.clear()
278
                    term.setCursorPos(1,1)
279
                    shell.run(chosen.cmd)
280
                end
281
            end
282
        elseif event == "timer" then
283
            timer = os.startTimer(refreshRate)
284
            drawTopBar()
285
        end
286
    end
287
end
288
289
-- ===== START SIGNAL UPDATER IN PARALLEL WITH MAIN LOOP =====
290
parallel.waitForAny(updateSignal, mainLoop)
291