1+ name = " Terminal"
2+ description = " Terminal script for Minecraft using the games chat. (Not a real terminal, just lets you run commands in the chat from any screen.)"
3+
4+ function sendMessageToChat (message )
5+ client .execute (" say " .. message )
6+ end
7+
8+ function sendCommandToChat (command )
9+ client .execute (" execute " .. command )
10+ end
11+
12+ function sendOnixCommandToChat (command )
13+ client .execute (command )
14+ end
15+
16+ isHudScreen = false
17+
18+ function render3d ()
19+ isHudScreen = gui .screen () == " hud_screen" or gui .screen () == " chat_screen"
20+ end
21+
22+ textbox = gui .newTextbox (" " , " Command:" , 1024 )
23+ function postInit ()
24+ end
25+
26+ renderEverywhere = true
27+ previousCommands = {}
28+ currentCommandIndex = 0
29+
30+ terminalVisible = false
31+ terminalAnimationStartTime = 0
32+ terminalAnimationDuration = 250
33+ terminalClosing = false
34+ terminalTimeoutTime = 0
35+
36+ buttonVisible = true
37+ buttonAnimationStartTime = 0
38+ buttonAnimationDuration = 400
39+ buttonSize = 20
40+ buttonVisibleHeight = 5
41+ buttonHovered = false
42+ buttonHoverScale = 1.15
43+ buttonHoverAnimation = 0
44+ buttonHoverAnimationSpeed = 5
45+ buttonPulse = 0
46+ buttonPulseDir = 1
47+ buttonPulseSpeed = 0.02
48+ buttonLastFrame = os.clock ()
49+ lastHoverState = false
50+
51+ function easeOutBack (x )
52+ local c1 = 1.70158
53+ local c3 = c1 + 1
54+
55+ return 1 + c3 * math.pow (x - 1 , 3 ) + c1 * math.pow (x - 1 , 2 )
56+ end
57+
58+ function easeInBack (x )
59+ local c1 = 1.70158
60+ local c3 = c1 + 1
61+
62+ return c3 * x * x * x - c1 * x * x
63+ end
64+
65+ function getTerminalAnimationProgress ()
66+ local currentTime = os.clock () * 1000
67+ local elapsed = currentTime - terminalAnimationStartTime
68+ local progress = math.min (elapsed / terminalAnimationDuration , 1 )
69+
70+ if terminalClosing and elapsed >= terminalAnimationDuration and currentTime >= terminalTimeoutTime then
71+ terminalVisible = false
72+ terminalClosing = false
73+
74+ showButton ()
75+ end
76+
77+ if terminalVisible then
78+ if terminalClosing then
79+ return 1 - easeInBack (progress )
80+ else
81+ return easeOutBack (progress )
82+ end
83+ else
84+ return 0
85+ end
86+ end
87+
88+ function getButtonAnimationProgress ()
89+ local currentTime = os.clock () * 1000
90+ local elapsed = currentTime - buttonAnimationStartTime
91+ local progress = math.min (elapsed / buttonAnimationDuration , 1 )
92+
93+ if buttonVisible then
94+ return easeOutBack (progress )
95+ else
96+ return 1 - easeInBack (progress )
97+ end
98+ end
99+
100+ function getTerminalPosition ()
101+ local screenWidth = gui .width ()
102+ local screenHeight = gui .height ()
103+ local terminalWidth = 200
104+ local terminalHeight = 20
105+
106+ local targetY = screenHeight - terminalHeight - 10
107+ local hiddenY = screenHeight + 10
108+
109+ local progress = getTerminalAnimationProgress ()
110+ local currentY = hiddenY - (hiddenY - targetY ) * progress
111+
112+ return {
113+ x = (screenWidth - terminalWidth ) / 2 ,
114+ y = currentY ,
115+ w = terminalWidth ,
116+ h = terminalHeight
117+ }
118+ end
119+
120+ function getButtonPosition ()
121+ local screenWidth = gui .width ()
122+ local screenHeight = gui .height ()
123+
124+ return {
125+ x = (screenWidth - buttonSize ) / 2 ,
126+ y = screenHeight - buttonVisibleHeight ,
127+ w = buttonSize ,
128+ h = buttonSize
129+ }
130+ end
131+
132+ function isMouseOverButton ()
133+ if not buttonVisible then return false end
134+
135+ local btnPos = getButtonPosition ()
136+ local mX , mY = gui .mousex (), gui .mousey ()
137+
138+ return mX >= btnPos .x and mX <= btnPos .x + btnPos .w and mY >= btnPos .y and mY <= btnPos .y + buttonSize
139+ end
140+
141+ function showTerminal ()
142+ terminalVisible = true
143+ terminalClosing = false
144+ terminalAnimationStartTime = os.clock () * 1000
145+ hideButton ()
146+ end
147+
148+ function hideTerminal ()
149+ if terminalVisible and not terminalClosing then
150+ terminalClosing = true
151+ terminalAnimationStartTime = os.clock () * 1000
152+ terminalTimeoutTime = terminalAnimationStartTime + terminalAnimationDuration + 50
153+ textbox .focused = false
154+ end
155+ end
156+
157+ function showButton ()
158+ buttonVisible = true
159+ buttonAnimationStartTime = os.clock () * 1000
160+ end
161+
162+ function hideButton ()
163+ buttonVisible = false
164+ buttonAnimationStartTime = os.clock () * 1000
165+ end
166+
167+ function toggleTerminal ()
168+ if terminalVisible then
169+ hideTerminal ()
170+ else
171+ showTerminal ()
172+ end
173+ end
174+
175+ function closeTerminal ()
176+ hideTerminal ()
177+ end
178+
179+ function render2 ()
180+ if isHudScreen or textbox == nil then return end
181+
182+ local now = os.clock ()
183+ local delta = now - buttonLastFrame
184+ buttonLastFrame = now
185+
186+ local currentHoverState = isMouseOverButton ()
187+
188+ if currentHoverState ~= lastHoverState then
189+ lastHoverState = currentHoverState
190+ end
191+
192+ if currentHoverState then
193+ buttonHoverAnimation = math.min (1 , buttonHoverAnimation + (buttonHoverAnimationSpeed * delta ))
194+ else
195+ buttonHoverAnimation = math.max (0 , buttonHoverAnimation - (buttonHoverAnimationSpeed * delta ))
196+ end
197+
198+ buttonPulse = buttonPulse + (buttonPulseSpeed * buttonPulseDir * delta * 60 )
199+ if buttonPulse > 1 then
200+ buttonPulse = 1
201+ buttonPulseDir = - 1
202+ elseif buttonPulse < 0 then
203+ buttonPulse = 0
204+ buttonPulseDir = 1
205+ end
206+
207+ local pos = getTerminalPosition ()
208+
209+ if getTerminalAnimationProgress () > 0 then
210+ textbox :render (pos .x , pos .y , pos .w , pos .h )
211+ end
212+
213+ local btnAnimProgress = getButtonAnimationProgress ()
214+
215+ if btnAnimProgress > 0 then
216+ local btnPos = getButtonPosition ()
217+
218+ local hoverEffectScale = 1 + ((buttonHoverScale - 1 ) * easeOutBack (buttonHoverAnimation ))
219+
220+ local btnScale = btnAnimProgress * hoverEffectScale
221+
222+ local btnCenterX = btnPos .x + btnPos .w / 2
223+ local btnCenterY = btnPos .y + btnPos .h / 2
224+ local btnSizeAnimated = buttonSize * btnScale
225+
226+ local animatedBtnX = btnCenterX - (btnSizeAnimated / 2 )
227+ local animatedBtnY = btnPos .y + buttonSize - btnSizeAnimated
228+
229+ local hoverColorBoost = math.floor (20 * buttonHoverAnimation )
230+ local pulseInfluence = math.sin (now * 4 ) * 0.1
231+ local arrowBounce = math.sin (now * 4 ) * buttonHoverAnimation * 0.8
232+
233+ gfx2 .color (25 + hoverColorBoost , 25 + hoverColorBoost , 25 + hoverColorBoost , 200 * btnAnimProgress )
234+ gfx2 .fillRoundRect (animatedBtnX , animatedBtnY , btnSizeAnimated , btnSizeAnimated , 5 )
235+
236+ local pulseAmount = 10 + (10 * buttonHoverAnimation )
237+ local pulseColor = math.floor (pulseAmount * (0.5 + pulseInfluence ))
238+ gfx2 .color (255 + pulseColor , 255 + pulseColor , 255 + pulseColor , 114.75 * btnAnimProgress )
239+ gfx2 .drawRoundRect (animatedBtnX , animatedBtnY , btnSizeAnimated , btnSizeAnimated , 5 , 0.5 )
240+
241+ gfx2 .color ( 25 + math.floor (10 * buttonHoverAnimation ), 23 + math.floor (10 * buttonHoverAnimation ), 22 + math.floor (10 * buttonHoverAnimation ), 255 * btnAnimProgress )
242+ gfx2 .fillTriangle ( btnCenterX - 5 * btnScale , btnCenterY + (2 - arrowBounce ) * btnScale , btnCenterX + 5 * btnScale , btnCenterY + (2 - arrowBounce ) * btnScale , btnCenterX , btnCenterY + (- 3 - arrowBounce ) * btnScale )
243+ end
244+ end
245+
246+ event .listen (" MouseInput" , function (button , down )
247+ if isHudScreen then return end
248+
249+ if button == 1 and down then
250+ local mX , mY = gui .mousex (), gui .mousey ()
251+ local pos = getTerminalPosition ()
252+
253+ if terminalVisible and mX >= pos .x and mX <= pos .x + pos .w and mY >= pos .y and mY <= pos .y + pos .h then
254+ textbox .focused = true
255+ return
256+ else
257+ textbox .focused = false
258+ if terminalVisible and not terminalClosing then
259+ hideTerminal ()
260+ end
261+ end
262+
263+ local btnPos = getButtonPosition ()
264+ if buttonVisible and mX >= btnPos .x and mX <= btnPos .x + btnPos .w and mY >= btnPos .y and mY <= btnPos .y + buttonSize then
265+ toggleTerminal ()
266+ gui .clickSound ()
267+ return
268+ end
269+ end
270+ end )
271+
272+ event .listen (" KeyboardInput" , function (key , down )
273+ if isHudScreen then return end
274+ if textbox .focused then
275+ if key == 13 and down == false then
276+ local command = textbox .text
277+ if command :sub (1 , 1 ) == " /" then
278+ sendCommandToChat (command :sub (2 ))
279+ elseif command :sub (1 , 1 ) == " ." then
280+ sendOnixCommandToChat (command :sub (2 ))
281+ else
282+ sendMessageToChat (command )
283+ end
284+ table.insert (previousCommands , command )
285+ textbox .text = " "
286+ currentCommandIndex = 0
287+ end
288+ if key == 38 and down then
289+ if # previousCommands > 0 then
290+ if currentCommandIndex < # previousCommands then
291+ currentCommandIndex = currentCommandIndex + 1
292+ end
293+ textbox .text = previousCommands [# previousCommands - currentCommandIndex + 1 ]
294+ end
295+ end
296+ if key == 40 and down then
297+ if currentCommandIndex > 0 then
298+ currentCommandIndex = currentCommandIndex - 1
299+ if currentCommandIndex == 0 then
300+ textbox .text = " "
301+ else
302+ textbox .text = previousCommands [# previousCommands - currentCommandIndex + 1 ]
303+ end
304+ end
305+ end
306+ return true
307+ end
308+
309+ if key == 192 and down then
310+ toggleTerminal ()
311+ return true
312+ end
313+
314+ if key == 27 and down and terminalVisible and not terminalClosing then
315+ hideTerminal ()
316+ return true
317+ end
318+ end )
0 commit comments