· 9 years ago · Jan 15, 2017, 12:00 AM
1--[[
2 KrystalDance: MLG edit No. 3 by adchand2
3 credit to everyone...
4 New updates (from MLG3 to MLG3 v2): Fixed this script detecting head incorrectly.
5
6 © 2016-17 adchand2/memesbruh03.
7 ]]
8
9
10print("Hello World!")
11 print(5)
12 print(Game.Workspace.Baseplate.BrickColor)
13 game.Workspace.Baseplate.Transparency = .5
14 print(game.Workspace.Baseplate.Name)
15
16 local myBasePlate = game.Workspace.Baseplate
17
18 local function makeBasePlateRed(message)
19 myBasePlate.CanCollide = false
20 myBasePlate.BrickColor = BrickColor.Red()
21 print(message)
22end
23
24 myBasePlate.CanCollide = true
25 myBasePlate.BrickColor = BrickColor.Green()
26
27 local score = 0
28
29 makeBasePlateRed("Hey, Im Red Now!")
30
31wait(0)
32Player = game.Players.LocalPlayer
33WorkPlayer = workspace:FindFirstChild(Player.Name)
34
35local count = 0
36local countspeed = 1
37local sine = 0
38local sinespeed = 1
39local angle = nil
40local global_wait = 0
41local showtag = true
42local smode = 1
43local advan = false
44local forcheck = 0
45-- Smodes: 1 = Original, 2 = Others, 3 = From the 1st Edit
46
47function inform2(var)
48t=game:GetService("Chat")
49t:Chat(WorkPlayer.FalseHead,var,math.random(0,2))
50end
51
52--dance booleans--
53local unity = false -- jawn
54local _2_much_power = false -- harlem_dank
55local some_power = false -- nova_fire
56local haha_no = false -- this_is_epic
57local spin_round = false -- gta_loud
58local still_not_that_fast = false -- sanic_x
59local tetris_remix = false -- mlg_dubbs
60local dat_boi = false -- _2204355
61local memes = false -- mlg_style
62local scary_monsters_nice_sprites_remix = false -- paper_mario
63local rus = false -- otis
64local it_s_already_that_old = false -- LJN
65local pootis_avi = false -- ITS_NO_USE
66local buelah_mp3 = false -- spm
67local antivirisis = false -- stylo
68local look_at_this_dude = false -- nedm
69------------------
70--dance accessory--
71local barrelbrick = nil
72local saxtool = nil
73-------------------
74--custom animate--
75local walk = false
76local jump = false
77local sit = false
78local run = false
79------------------
80--walk keys--
81local W = false
82local A = false
83local S = false
84local D = false
85-------------
86local m = Instance.new("Model",game.Players.LocalPlayer.Character) m.Name = "ModelParts"
87local miniweld = nil
88local rootpart = nil
89
90local Mouse = nil
91local Animate = nil
92local Music = nil
93local Asset = "http://www.roblox.com/asset/?id="
94local Animating = nil
95local humanoid = nil
96local face = nil
97
98local head = nil
99local torso = nil
100local ra = nil
101local la = nil
102local rl = nil
103local ll = nil
104local rs = nil
105local ls = nil
106local rh = nil
107local lh = nil
108local neck = nil
109local rj = nil
110
111local char = nil
112local Hat1 = nil
113local Hat2 = nil
114local a,b = nil
115
116----------musics-----------------
117local M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16 = nil
118---------------------------------
119
120local mesh,meshids,textureids,w
121
122
123
124function get_sets()
125 PerpMode = 'Refresh'
126 AccMode = false
127 ImpactDebuff = true
128 MeleeMode = false
129 Test = 0
130 StartLockStyle = '73'
131
132 Buff_BPs_Healing = S{'Healing Ruby','Healing Ruby II','Whispering Wind','Spring Water'}
133 Debuff_BPs = S{'Mewing Lullaby','Eerie Eye','Lunar Cry','Lunar Roar','Nightmare','Pavor Nocturnus','Ultimate Terror','Somnolence','Slowga','Tidal Roar','Diamond Storm','Sleepga','Shock Squall'}
134
135 Magic_BPs_NoTP = S{'Holy Mist','Nether Blast','Aerial Blast','Searing Light','Diamond Dust','Earthen Fury','Zantetsuken','Tidal Wave','Judgment Bolt','Inferno','Howling Moon','Ruinous Omen','Night Terror','Thunderspark'}
136 Magic_BPs_TP = S{'Impact','Conflag Strike','Level ? Holy','Lunar Bay','Meteor Strike','Geocrush','Grand Fall','Wind Blade','Heavenly Strike','Thunderstorm'}
137 Physical_BPs_TP = S{'Rock Buster','Mountain Buster','Crescent Fang','Spinning Dive'}
138
139 AvatarList = S{'Shiva','Ramuh','Garuda','Leviathan','Diabolos','Titan','Fenrir','Ifrit','Carbuncle','Fire Spirit','Air Spirit','Ice Spirit','Thunder Spirit','Light Spirit','Dark Spirit','Earth Spirit','Water Spirit','Cait Sith','Alexander','Odin','Atomos'}
140 TownIdle = S{"windurst woods","windurst waters","windurst walls","port windurst","bastok markets","bastok mines","port bastok","southern san d'oria","northern san d'oria","port san d'oria","upper jeuno","lower jeuno","port jeuno","ru'lude gardens","norg","kazham","tavnazian safehold","rabao","selbina","mhaura","aht urhgan whitegate","al zahbi","nashmau","western adoulin","eastern adoulin"}
141 Salvage = S{"Bhaflau Remnants","Zhayolm Remnants","Arrapago Remnants","Silver Sea Remnants"}
142
143 sets.precast = {}
144
145 sets.precast.FC = {
146 main="Oranyan",
147 sub="Clerisy Strap +1",
148 --ammo="Sapience Orb",
149 head="Nahtirah Hat",
150 neck="Orunmila's Torque",
151 ear1="Loquacious Earring",
152 ear2="Etiolation Earring",
153 hands={ name="Telchine Gloves", augments={'"Fast Cast"+5','Enh. Mag. eff. dur. +8',}},
154 body="Inyanga Jubbah +1",
155 ring1="Lebeche Ring",
156 ring2="Kishar Ring",
157 back={ name="Campestres's Cape", augments={'"Fast Cast"+10',}},
158 waist="Witful Belt",
159 legs="Lengo Pants",
160 feet="Regal Pumps +1"
161 }
162
163 sets.midcast = {}
164
165 -- BP Timer Gear
166 sets.midcast.BP = {
167 --main={ name="Espiritus", augments={'Summoning magic skill +15','Pet: Mag. Acc.+30','System: 2 ID: 153 Val: 3',}},
168 sub="Vox Grip",
169 ammo="Sancus Sachet +1",
170 head="Beckoner's Horn +1",
171 neck="Incanter's Torque",
172 ear1="Evans Earring",
173 ear2="Andoaa Earring",
174 body="Apogee Dalmatica +1",
175 hands="Glyphic Bracers +1",
176 ring1="Evoker's Ring",
177 ring2="Globidonta Ring",
178 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
179 waist="Kobo Obi",
180 legs="Beckoner's Spats +1",
181 feet="Apogee Pumps"
182 }
183
184 sets.midcast.Siphon_Base = {
185 main={ name="Espiritus", augments={'Summoning magic skill +15','Pet: Mag. Acc.+30','System: 2 ID: 153 Val: 3',}},
186 sub="Vox Grip",
187 ammo="Esper Stone +1",
188 head={ name="Telchine Cap", augments={'Pet: "Mag.Atk.Bns."+19','"Elemental Siphon"+25','Enh. Mag. eff. dur. +9',}},
189 neck="Incanter's Torque",
190 ear1="Smn. Earring",
191 ear2="Andoaa Earring",
192 body={ name="Telchine Chas.", augments={'Pet: Mag. Acc.+16','"Elemental Siphon"+35',}},
193 hands="Lamassu Mitts +1",
194 ring1="Evoker's Ring",
195 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
196 waist="Kobo Obi",
197 legs="Beckoner's Spats +1",
198 feet="Beck. Pigaches +1"
199 }
200
201 sets.midcast.Siphon = set_combine(sets.midcast.Siphon_Base, { ring2="Globidonta Ring" })
202
203 sets.midcast.SiphonZodiac = set_combine(sets.midcast.Siphon_Base, { ring2="Zodiac Ring" })
204
205 sets.midcast.Cure = {
206 main="Nirvana",
207 sub="Oneiros Grip",
208 ammo="Sancus Sachet +1",
209 head={ name="Vanya Hood", augments={'MP+50','"Cure" potency +7%','Enmity-6',}},
210 neck="Fylgja Torque +1",
211 ear1="Roundel Earring",
212 ear2="Novia Earring",
213 body="Witching Robe",
214 hands={ name="Telchine Gloves", augments={'"Fast Cast"+5','Enh. Mag. eff. dur. +8',}},
215 ring1="Lebeche Ring",
216 ring2="Haoma's Ring",
217 back="Tempered Cape +1",
218 waist="Witful Belt",
219 legs="Assiduity Pants +1",
220 feet="Vanya Clogs"
221 }
222
223 sets.midcast.Cursna = set_combine(sets.precast.FC, {
224 neck="Debilis Medallion",
225 ear1="Healing Earring",
226 ear2="Beatific Earring",
227 ring1="Haoma's Ring",
228 ring2="Haoma's Ring",
229 back="Tempered Cape +1",
230 waist="Bishop's Sash"
231 })
232
233 sets.midcast.EnmityRecast = {
234 main="Nirvana",
235 sub="Oneiros Grip",
236 ear1="Novia Earring",
237 body="Witching Robe",
238 hands={ name="Helios Gloves", augments={'Pet: Accuracy+22 Pet: Rng. Acc.+22','Pet: "Dbl. Atk."+8','Pet: Haste+6',}},
239 legs="Assiduity Pants +1",
240 feet={ name="Helios Boots", augments={'Pet: Accuracy+21 Pet: Rng. Acc.+21','Pet: "Dbl. Atk."+8','Pet: Haste+6',}}
241 }
242
243 sets.midcast.Enfeeble = {
244 main="Oranyan",
245 sub="Enki Strap",
246 head="Befouled Crown",
247 neck="Erra Pendant",
248 ear1="Dignitary's Earring",
249 ear2="Gwati Earring",
250 body="Vanya Robe",
251 hands="Inyanga Dastanas +1",
252 ring1="Stikini Ring",
253 ring2="Stikini Ring",
254 back="Aurist's Cloak +1",
255 waist="Luminary Sash",
256 legs="Inyanga Shalwar +1",
257 feet="Skaoi Boots"
258 }
259
260 sets.midcast.Enhancing = {
261 main="Gada",
262 sub="Ammurapi Shield",
263 head={ name="Telchine Cap", augments={'Pet: "Mag.Atk.Bns."+19','"Elemental Siphon"+25','Enh. Mag. eff. dur. +9',}},
264 neck="Incanter's Torque",
265 ear1="Augmenting Earring",
266 ear2="Andoaa Earring",
267 body={ name="Telchine Chas.", augments={'"Conserve MP"+5','Enh. Mag. eff. dur. +10',}},
268 hands={ name="Telchine Gloves", augments={'"Fast Cast"+5','Enh. Mag. eff. dur. +8',}},
269 ring1="Stikini Ring",
270 ring2="Stikini Ring",
271 back="Merciful Cape",
272 waist="Olympus Sash",
273 legs="Shedir Seraweels",
274 feet={ name="Telchine Pigaches", augments={'"Conserve MP"+3','Enh. Mag. eff. dur. +9',}}
275 }
276
277 sets.midcast.Nuke = {
278 main="Oranyan",
279 sub="Niobid Strap",
280 head="Buremte Hat",
281 neck="Eddy Necklace",
282 ear1="Hecate's Earring",
283 ear2="Friomisi Earring",
284 body="Witching Robe",
285 hands="Hagondes Cuffs +1",
286 ring1="Demon's Ring",
287 ring2="Strendu Ring",
288 back="Toro Cape",
289 waist="Sekhmet Corset",
290 legs="Hagondes Pants +1",
291 feet="Umbani Boots"
292 }
293
294 sets.midcast["Mana Cede"] = { hands="Beckoner's Bracers" }
295
296 sets.midcast["Astral Flow"] = { head="Glyphic Horn +1" }
297
298 sets.midcast["Shattersoul"] = {
299 neck="Fotia Gorget",
300 ear1="Zennaroi Earring",
301 ear2="Telos Earring",
302 ring1="Rajas Ring",
303 ring2="Mars's Ring",
304 back={ name="Campestres's Cape", augments={'Pet: M.Acc.+20 Pet: M.Dmg.+20','Accuracy+20 Attack+20','Pet: Mag. Acc.+10','"Dbl.Atk."+10',}},
305 waist="Fotia Belt",
306 legs={ name="Telchine Braconi", augments={'Accuracy+17','Weapon Skill Acc.+14','Weapon skill damage +3%',}},
307 feet="Merlinic Crackows"
308 }
309
310 sets.midcast["Cataclysm"] = sets.midcast.Nuke
311
312 sets.midcast["Garland of Bliss"] = sets.midcast.Nuke
313
314 sets.pet_midcast = {}
315
316 sets.pet_midcast.Physical_BP = {
317 main="Nirvana",
318 sub="Elan Strap +1",
319 ammo="Sancus Sachet +1",
320 head={ name="Apogee Crown +1", augments={'MP+80','Pet: Attack+35','Blood Pact Dmg.+8',}},
321 neck="Shulmanu Collar",
322 ear1="Lugalbanda Earring",
323 ear2="Gelos Earring",
324 body="Convoker's Doublet +2",
325 hands={ name="Merlinic Dastanas", augments={'Pet: Attack+24 Pet: Rng.Atk.+24','Blood Pact Dmg.+9','Pet: STR+10','Pet: Mag. Acc.+7',}},
326 ring1="Varar Ring +1",
327 ring2="Varar Ring +1",
328 back={ name="Campestres's Cape", augments={'Pet: Acc.+20 Pet: R.Acc.+20 Pet: Atk.+20 Pet: R.Atk.+20','Eva.+20 /Mag. Eva.+20','Pet: Attack+10 Pet: Rng.Atk.+10','Pet: "Regen"+10',}},
329 waist="Incarnation Sash",
330 legs="Apogee Slacks +1",
331 feet={ name="Apogee Pumps +1", augments={'MP+80','Pet: Attack+35','Blood Pact Dmg.+8',}}
332 }
333
334 sets.pet_midcast.Physical_BP_TP = set_combine(sets.pet_midcast.Physical_BP, {
335 legs="Enticer's Pants"
336 })
337
338 sets.pet_midcast.Physical_BP_Acc = set_combine(sets.pet_midcast.Physical_BP, {
339 hands="Glyphic Bracers +1",
340 ring2="Thurandaut Ring",
341 legs={ name="Helios Spats", augments={'Pet: Accuracy+25 Pet: Rng. Acc.+25','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}},
342 feet={ name="Helios Boots", augments={'Pet: Accuracy+27 Pet: Rng. Acc.+27','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}}
343 })
344
345 sets.pet_midcast.Physical_BP_Crit = set_combine(sets.pet_midcast.Physical_BP, {
346 head={ name="Helios Band", augments={'Pet: Accuracy+26 Pet: Rng. Acc.+26','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}},
347 body="Glyphic Doublet +1",
348 feet={ name="Helios Boots", augments={'Pet: Accuracy+27 Pet: Rng. Acc.+27','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}}
349 })
350
351 sets.pet_midcast.Magic_BP_Base = {
352 main={ name="Grioavolr", augments={'Blood Pact Dmg.+5','Pet: INT+10','Pet: Mag. Acc.+22','Pet: "Mag.Atk.Bns."+21',}},
353 sub="Elan Strap +1",
354 ammo="Sancus Sachet +1",
355 head={ name="Apogee Crown +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}},
356 neck="Adad Amulet",
357 ear1="Lugalbanda Earring",
358 ear2="Gelos Earring",
359 body="Apogee Dalmatica +1",
360 hands={ name="Merlinic Dastanas", augments={'Pet: "Mag.Atk.Bns."+29','Blood Pact Dmg.+10','Pet: DEX+2',}},
361 ring1="Varar Ring +1",
362 ring2="Varar Ring +1",
363 back={ name="Campestres's Cape", augments={'Pet: M.Acc.+20 Pet: M.Dmg.+20','Accuracy+20 Attack+20','Pet: Mag. Acc.+10','"Dbl.Atk."+10',}},
364 waist="Incarnation Sash",
365 feet={ name="Apogee Pumps +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}}
366 }
367
368 sets.pet_midcast.Magic_BP_TP = set_combine(sets.pet_midcast.Magic_BP_Base, {
369 legs="Enticer's Pants"
370 })
371
372 sets.pet_midcast.Magic_BP_NoTP = set_combine(sets.pet_midcast.Magic_BP_Base, {
373 legs={ name="Helios Spats", augments={'Pet: "Mag.Atk.Bns."+30','Pet: "Dbl. Atk."+7','Blood Pact Dmg.+7',}}
374 })
375
376 sets.pet_midcast.Magic_BP_TP_Acc = set_combine(sets.pet_midcast.Magic_BP_TP, {
377 head={ name="Merlinic Hood", augments={'Pet: Mag. Acc.+21 Pet: "Mag.Atk.Bns."+21','Blood Pact Dmg.+7','Pet: INT+6','Pet: "Mag.Atk.Bns."+11',}},
378 body={ name="Merlinic Jubbah", augments={'Pet: Mag. Acc.+24 Pet: "Mag.Atk.Bns."+24','Blood Pact Dmg.+7','Pet: INT+6',}}
379 })
380
381 sets.pet_midcast.Magic_BP_NoTP_Acc = set_combine(sets.pet_midcast.Magic_BP_NoTP, {
382 head={ name="Merlinic Hood", augments={'Pet: Mag. Acc.+21 Pet: "Mag.Atk.Bns."+21','Blood Pact Dmg.+7','Pet: INT+6','Pet: "Mag.Atk.Bns."+11',}},
383 body={ name="Merlinic Jubbah", augments={'Pet: Mag. Acc.+24 Pet: "Mag.Atk.Bns."+24','Blood Pact Dmg.+7','Pet: INT+6',}}
384 })
385
386 sets.pet_midcast.Magic_BP_Test1 = sets.pet_midcast.Magic_BP_TP
387
388 sets.pet_midcast.Magic_BP_Test2 = set_combine(sets.pet_midcast.Magic_BP_TP, {
389 main={ name="Grioavolr", augments={'Blood Pact Dmg.+3','Pet: VIT+12','Pet: Mag. Acc.+16','Pet: "Mag.Atk.Bns."+29',}}
390 })
391
392 sets.pet_midcast.FlamingCrush = {
393 main="Nirvana",
394 sub="Elan Strap +1",
395 ammo="Sancus Sachet +1",
396 head={ name="Apogee Crown +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}},
397 neck="Adad Amulet",
398 ear1="Lugalbanda Earring",
399 ear2="Gelos Earring",
400 body="Apogee Dalmatica +1",
401 hands={ name="Merlinic Dastanas", augments={'Pet: "Mag.Atk.Bns."+29','Blood Pact Dmg.+10','Pet: DEX+2',}},
402 ring1="Varar Ring +1",
403 ring2="Varar Ring +1",
404 back={ name="Campestres's Cape", augments={'Pet: Acc.+20 Pet: R.Acc.+20 Pet: Atk.+20 Pet: R.Atk.+20','Eva.+20 /Mag. Eva.+20','Pet: Attack+10 Pet: Rng.Atk.+10','Pet: "Regen"+10',}},
405 waist="Incarnation Sash",
406 --legs={ name="Helios Spats", augments={'Pet: "Mag.Atk.Bns."+30','Pet: "Dbl. Atk."+7','Blood Pact Dmg.+7',}},
407 legs="Apogee Slacks +1",
408 feet={ name="Apogee Pumps +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}}
409 }
410
411 sets.pet_midcast.FlamingCrush_Acc = set_combine(sets.pet_midcast.FlamingCrush, {
412 body="Convoker's Doublet +2",
413 ring2="Thurandaut Ring",
414 legs={ name="Helios Spats", augments={'Pet: Accuracy+25 Pet: Rng. Acc.+25','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}},
415 feet={ name="Helios Boots", augments={'Pet: Accuracy+27 Pet: Rng. Acc.+27','Pet: Crit.hit rate +4','Blood Pact Dmg.+7',}}
416 })
417
418 sets.pet_midcast.MagicAcc_BP = {
419 main="Nirvana",
420 sub="Vox Grip",
421 ammo="Sancus Sachet +1",
422 head={ name="Helios Band", augments={'Pet: Mag. Acc.+29','"Blood Pact" ability delay -5','Summoning magic skill +8',}},
423 neck="Incanter's Torque",
424 ear1="Lugalbanda Earring",
425 ear2="Andoaa Earring",
426 body="Tali'ah Manteel +1",
427 hands="Lamassu Mitts +1",
428 ring1="Evoker's Ring",
429 ring2="Globidonta Ring",
430 back={ name="Campestres's Cape", augments={'Pet: M.Acc.+20 Pet: M.Dmg.+20','Accuracy+20 Attack+20','Pet: Mag. Acc.+10','"Dbl.Atk."+10',}},
431 waist="Incarnation Sash",
432 legs={ name="Helios Spats", augments={'Pet: Mag. Acc.+25','"Blood Boon"+5','Summoning magic skill +6',}},
433 feet={ name="Helios Boots", augments={'Pet: Mag. Acc.+29','"Blood Pact" ability delay -5','Summoning magic skill +8',}}
434 }
435
436 sets.pet_midcast.SummoningMagic = {
437 main={ name="Espiritus", augments={'Summoning magic skill +15','Pet: Mag. Acc.+30','System: 2 ID: 153 Val: 3',}},
438 sub="Vox Grip",
439 ammo="Sancus Sachet +1",
440 head="Convoker's Horn +1",
441 neck="Incanter's Torque",
442 ear1="Smn. Earring",
443 ear2="Andoaa Earring",
444 body="Beckoner's Doublet +1",
445 hands="Lamassu Mitts +1",
446 ring1="Evoker's Ring",
447 ring2="Globidonta Ring",
448 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
449 waist="Kobo Obi",
450 legs="Beckoner's Spats +1",
451 feet="Apogee Pumps"
452 }
453
454 sets.pet_midcast.Buff = set_combine(sets.pet_midcast.SummoningMagic, {
455 head="Beckoner's Horn +1"
456 })
457
458 sets.pet_midcast.Buff_Healing = set_combine(sets.pet_midcast.SummoningMagic, {
459 main="Nirvana",
460 head={ name="Apogee Crown +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}},
461 body="Apogee Dalmatica +1",
462 feet={ name="Apogee Pumps +1", augments={'MP+80','Pet: "Mag.Atk.Bns."+35','Blood Pact Dmg.+8',}}
463 })
464
465 sets.pet_midcast.Impact = {
466 main="Nirvana",
467 sub="Vox Grip",
468 ammo="Sancus Sachet +1",
469 head="Convoker's Horn +1",
470 neck="Incanter's Torque",
471 ear1="Smn. Earring",
472 ear2="Andoaa Earring",
473 body="Beckoner's Doublet +1",
474 hands="Lamassu Mitts +1",
475 ring1="Evoker's Ring",
476 ring2="Globidonta Ring",
477 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
478 waist="Lucidity Sash",
479 legs="Beckoner's Spats +1",
480 feet="Apogee Pumps"
481 }
482
483 sets.aftercast = {}
484
485 sets.aftercast.None = {
486 main="Nirvana",
487 sub="Oneiros Grip",
488 ammo="Sancus Sachet +1",
489 head="Beckoner's Horn +1",
490 neck="Loricate Torque +1",
491 ear1="Moonshade Earring",
492 ear2="Etiolation Earring",
493 body="Apogee Dalmatica +1",
494 hands="Asteria Mitts +1",
495 ring1="Defending Ring",
496 ring2="Dark Ring",
497 back="Umbra Cape",
498 waist="Slipor Sash",
499 legs="Assiduity Pants +1",
500 feet="Herald's Gaiters"
501 }
502
503 sets.aftercast.Perp_Favor = {
504 main="Nirvana",
505 sub="Oneiros Grip",
506 ammo="Sancus Sachet +1",
507 head="Beckoner's Horn +1",
508 neck="Caller's Pendant",
509 ear1="Moonshade Earring",
510 ear2="Andoaa Earring",
511 body="Beckoner's Doublet +1",
512 hands="Lamassu Mitts +1",
513 ring1="Evoker's Ring",
514 ring2="Globidonta Ring",
515 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
516 waist="Fucho-no-obi",
517 legs="Beckoner's Spats +1",
518 feet="Apogee Pumps"
519 }
520
521 sets.aftercast.Perp_Base = {
522 main="Nirvana",
523 sub="Oneiros Grip",
524 ammo="Sancus Sachet +1",
525 head="Beckoner's Horn +1",
526 neck="Caller's Pendant",
527 ear1="Moonshade Earring",
528 ear2="Evans Earring",
529 ring1="Evoker's Ring",
530 ring2="Thurandaut Ring",
531 back={ name="Campestres's Cape", augments={'Pet: Acc.+20 Pet: R.Acc.+20 Pet: Atk.+20 Pet: R.Atk.+20','Eva.+20 /Mag. Eva.+20','Pet: Attack+10 Pet: Rng.Atk.+10','Pet: "Regen"+10',}},
532 waist="Isa Belt",
533 legs="Assiduity Pants +1"
534 }
535
536 sets.aftercast.Perp_Normal = set_combine(sets.aftercast.Perp_Base, {
537 ear2="Rimeice Earring",
538 body="Glyphic Doublet +1",
539 hands={ name="Helios Gloves", augments={'Pet: Accuracy+22 Pet: Rng. Acc.+22','Pet: "Dbl. Atk."+8','Pet: Haste+6',}},
540 waist="Klouskap Sash",
541 feet={ name="Helios Boots", augments={'Pet: Accuracy+21 Pet: Rng. Acc.+21','Pet: "Dbl. Atk."+8','Pet: Haste+6',}}
542 })
543
544 sets.aftercast.Perp_Refresh = set_combine(sets.aftercast.Perp_Base, {
545 body="Apogee Dalmatica +1",
546 hands="Asteria Mitts +1",
547 feet="Merlinic Crackows"
548 })
549
550 sets.aftercast.Perp_RefreshSub50 = set_combine(sets.aftercast.Perp_Refresh, {
551 waist="Fucho-no-obi"
552 })
553
554 sets.aftercast.Perp_Melee = set_combine(sets.aftercast.Perp_Refresh, {
555 head="Tali'ah Turban +1",
556 neck="Lissome Necklace",
557 ear1="Telos Earring",
558 ear2="Cessance Earring",
559 body="Tali'ah Manteel +1",
560 hands="Tali'ah Gages +1",
561 ring1="Rajas Ring",
562 ring2="Petrov Ring",
563 back={ name="Campestres's Cape", augments={'Pet: M.Acc.+20 Pet: M.Dmg.+20','Accuracy+20 Attack+20','Pet: Mag. Acc.+10','"Dbl.Atk."+10',}},
564 waist="Klouskap Sash",
565 --legs="Tali'ah Seraweels +1",
566 feet="Tali'ah Crackows +1"
567 })
568
569 sets.aftercast.Avatar_DT = {
570 main="Nirvana",
571 sub="Oneiros Grip",
572 ammo="Sancus Sachet +1",
573 head="Selenian Cap",
574 neck="Empath Necklace",
575 ear1="Handler's Earring",
576 ear2="Handler's Earring +1",
577 body="Apogee Dalmatica +1",
578 hands="Artsieq Cuffs",
579 ring1="Evoker's Ring",
580 ring2="Thurandaut Ring",
581 back={ name="Campestres's Cape", augments={'Pet: Acc.+20 Pet: R.Acc.+20 Pet: Atk.+20 Pet: R.Atk.+20','Eva.+20 /Mag. Eva.+20','Pet: Attack+10 Pet: Rng.Atk.+10','Pet: "Regen"+10',}},
582 waist="Isa Belt",
583 legs="Assiduity Pants +1",
584 feet={ name="Telchine Pigaches", augments={'Pet: DEF+14','Pet: "Regen"+3','Pet: Damage taken -3%',}}
585 }
586
587 sets.aftercast.Spirit = {
588 main="Nirvana",
589 sub="Vox Grip",
590 ammo="Sancus Sachet +1",
591 head="Convoker's Horn +1",
592 neck="Caller's Pendant",
593 ear1="Smn. Earring",
594 ear2="Andoaa Earring",
595 body="Beckoner's Doublet +1",
596 hands="Lamassu Mitts +1",
597 ring1="Evoker's Ring",
598 ring2="Globidonta Ring",
599 back={ name="Conveyance Cape", augments={'Summoning magic skill +4','Pet: Enmity+6','Blood Pact ab. del. II -3',}},
600 waist="Lucidity Sash",
601 legs="Glyphic Spats +1",
602 feet="Merlinic Crackows"
603 }
604
605 -- Select initial macro set, helps when using "gs reload"
606 if pet.isvalid then
607 if pet.name=='Fenrir' then
608 send_command('input /macro book 10;wait .1;input /macro set 2;wait 3;input /lockstyleset '..StartLockStyle)
609 elseif pet.name=='Ifrit' then
610 send_command('input /macro book 10;wait .1;input /macro set 3;wait 3;input /lockstyleset '..StartLockStyle)
611 elseif pet.name=='Titan' then
612 send_command('input /macro book 10;wait .1;input /macro set 4;wait 3;input /lockstyleset '..StartLockStyle)
613 elseif pet.name=='Leviathan' then
614 send_command('input /macro book 10;wait .1;input /macro set 5;wait 3;input /lockstyleset '..StartLockStyle)
615 elseif pet.name=='Garuda' then
616 send_command('input /macro book 10;wait .1;input /macro set 6;wait 3;input /lockstyleset '..StartLockStyle)
617 elseif pet.name=='Shiva' then
618 send_command('input /macro book 10;wait .1;input /macro set 7;wait 3;input /lockstyleset '..StartLockStyle)
619 elseif pet.name=='Ramuh' then
620 send_command('input /macro book 10;wait .1;input /macro set 8;wait 3;input /lockstyleset '..StartLockStyle)
621 elseif pet.name=='Diabolos' then
622 send_command('input /macro book 10;wait .1;input /macro set 9;wait 3;input /lockstyleset '..StartLockStyle)
623 elseif pet.name=='Cait Sith' then
624 send_command('input /macro book 11;wait .1;input /macro set 2;wait 3;input /lockstyleset '..StartLockStyle)
625 end
626 else
627 send_command('input /macro book 10;wait .1;input /macro set 1;wait 3;input /lockstyleset '..StartLockStyle)
628 end
629end
630
631function pet_change(pet,gain)
632 idle()
633end
634
635function precast(spell)
636 if pet_midaction() or spell.type=="Item" then
637 return
638 end
639 -- Spell fast cast
640 if spell.action_type=="Magic" then
641 if spell.name=="Stoneskin" then
642 equip(sets.precast.FC,{hands="Carapacho Cuffs",waist="Siegel Sash"})
643 else
644 equip(sets.precast.FC)
645 end
646 end
647end
648
649function midcast(spell)
650 if pet_midaction() or spell.type=="Item" then
651 return
652 end
653 -- BP Timer gear needs to swap here
654 if spell.type=="BloodPactWard" or spell.type=="BloodPactRage" then
655 equip(sets.midcast.BP)
656 -- Spell Midcast & Potency Stuff
657 elseif spell.name=="Elemental Siphon" then
658 if pet.element=="Light" or pet.element=="Dark" then
659 equip(sets.midcast.Siphon)
660 else
661 equip(sets.midcast.SiphonZodiac)
662 end
663 elseif spell.type=="WhiteMagic" then
664 if string.find(spell.name,"Cure") or string.find(spell.name,"Curaga") then
665 equip(sets.midcast.Cure)
666 elseif string.find(spell.name,"Protect") or string.find(spell.name,"Shell") then
667 equip(sets.midcast.Enhancing,{ring2="Sheltered Ring"})
668 elseif spell.skill=="Enfeebling Magic" then
669 equip(sets.midcast.Enfeeble)
670 elseif spell.skill=="Enhancing Magic" then
671 if spell.name=="Stoneskin" then
672 equip(sets.midcast.Enhancing,{neck="Nodens Gorget",waist="Siegel Sash",legs="Shedir Seraweels"})
673 if buffactive["Stoneskin"] then
674 windower.send_command('wait 1;cancel 37;')
675 end
676 elseif spell.name=="Sneak" and buffactive["Sneak"] and spell.target.type=="SELF" then
677 windower.send_command('cancel 71;')
678 else
679 equip(sets.midcast.Enhancing)
680 end
681 end
682 elseif spell.type=="BlackMagic" then
683 if spell.skill=="Elemental Magic" then
684 equip(sets.midcast.Nuke)
685 end
686 elseif spell.type=="Ninjutsu" then
687 if spell.name=="Utsusemi: Ichi" then
688 if buffactive["Copy Image"] then
689 windower.send_command('wait 1;cancel 66;')
690 end
691 end
692 elseif spell.action_type=="Magic" then
693 equip(sets.midcast.EnmityRecast)
694 elseif sets.midcast[spell.english] then
695 equip(sets.midcast[spell.english])
696 else
697 idle()
698 end
699end
700
701function aftercast(spell)
702 if pet_midaction() or spell.type=="Item" then
703 return
704 end
705 if spell and (not spell.type or not string.find(spell.type,"BloodPact") and not AvatarList:contains(spell.name) or spell.interrupted) then
706 idle()
707 end
708end
709
710function status_change(new,old)
711 if new=="Idle" then
712 idle()
713 end
714end
715
716function buff_change(name,gain)
717 if name=="Quickening" then
718 idle()
719 end
720end
721
722function pet_midcast(spell)
723 if spell.name=="Perfect Defense" then
724 equip(sets.midcast.SummoningMagic)
725 elseif spell.type=="BloodPactWard" then
726 if Debuff_BPs:contains(spell.name) then
727 equip(sets.pet_midcast.MagicAcc_BP)
728 elseif Buff_BPs_Healing:contains(spell.name) then
729 equip(sets.pet_midcast.Buff_Healing)
730 else
731 equip(sets.pet_midcast.Buff)
732 end
733 elseif spell.type=="BloodPactRage" then
734 if spell.name=="Flaming Crush" then
735 if AccMode then
736 equip(sets.pet_midcast.FlamingCrush_Acc)
737 else
738 equip(sets.pet_midcast.FlamingCrush)
739 end
740 elseif ImpactDebuff and (spell.name=="Impact" or spell.name=="Conflag Strike") then
741 equip(sets.pet_midcast.Impact)
742 elseif Magic_BPs_TP:contains(spell.name) or string.find(spell.name," II") or string.find(spell.name," IV") then
743 if Test==1 then
744 equip(sets.pet_midcast.Magic_BP_Test1)
745 elseif Test==2 then
746 equip(sets.pet_midcast.Magic_BP_Test2)
747 elseif AccMode then
748 equip(sets.pet_midcast.Magic_BP_TP_Acc)
749 else
750 equip(sets.pet_midcast.Magic_BP_TP)
751 end
752 elseif Magic_BPs_NoTP:contains(spell.name) then
753 if AccMode then
754 equip(sets.pet_midcast.Magic_BP_NoTP_Acc)
755 else
756 equip(sets.pet_midcast.Magic_BP_NoTP)
757 end
758 else
759 if AccMode then
760 equip(sets.pet_midcast.Physical_BP_Acc)
761 elseif Physical_BPs_TP:contains(spell.name) then
762 equip(sets.pet_midcast.Physical_BP_TP)
763 else
764 equip(sets.pet_midcast.Physical_BP)
765 end
766 end
767 end
768end
769
770function pet_aftercast(spell)
771 idle()
772end
773
774function self_command(command)
775 PerpModeCommands = S{'Normal','Refresh','DT','Favor'}
776 is_valid = false
777
778 if PerpModeCommands:contains(command) then
779 PerpMode = command
780 is_valid = true
781 elseif command=="AccMode" then
782 AccMode = AccMode==false
783 is_valid = true
784 send_command('console_echo "AccMode: '..tostring(AccMode)..'"')
785 elseif command=="ImpactMode" then
786 ImpactDebuff = ImpactDebuff==false
787 is_valid = true
788 send_command('console_echo "Impact Debuff: '..tostring(ImpactDebuff)..'"')
789 elseif command=="MeleeMode" then
790 if MeleeMode then
791 MeleeMode = false
792 enable("main","sub")
793 send_command('console_echo "Melee Mode: false"')
794 else
795 MeleeMode = true
796 equip({main="Nirvana",sub="Elan Strap +1"})
797 disable("main","sub")
798 send_command('console_echo "Melee Mode: true"')
799 end
800 is_valid = true
801 elseif command=="TestMode" then
802 Test = Test + 1
803 if Test==3 then
804 Test = 0
805 end
806 is_valid = true
807 send_command('console_echo "Test Mode: '..tostring(Test)..'"')
808 end
809
810 if not is_valid then
811 send_command('console_echo "gs c {Normal|Refresh|DT|Favor} {AccMode} {ImpactMode} {MeleeMode}"')
812 end
813 idle()
814end
815
816function idle()
817 --if TownIdle:contains(world.area:lower()) then
818 -- return
819 --end
820 if pet.isvalid then
821 if string.find(pet.name,'Spirit') then
822 equip(sets.aftercast.Spirit)
823 elseif PerpMode=='DT' then
824 equip(sets.aftercast.Avatar_DT)
825 elseif PerpMode=='Favor' then
826 equip(sets.aftercast.Perp_Favor)
827 elseif PerpMode=='Refresh' then
828 if player.mpp < 50 then
829 equip(sets.aftercast.Perp_RefreshSub50)
830 else
831 equip(sets.aftercast.Perp_Refresh)
832 end
833 elseif MeleeMode then
834 equip(sets.aftercast.Perp_Melee)
835 elseif PerpMode=='Normal' then
836 equip(sets.aftercast.Perp_Normal)
837 end
838 -- Gaiters if Fleet Wind is up
839 if buffactive['Quickening'] then
840 equip({feet="Herald's Gaiters"})
841 end
842 else
843 equip(sets.aftercast.None)
844 end
845 -- Balrahn's Ring
846 if Salvage:contains(world.area) then
847 equip({ring2="Balrahn's Ring"})
848 end
849end
850
851function fm(parent,meshid,x,y,z,meshtexture)
852if meshid == "cylinder" then
853 mesh = Instance.new("CylinderMesh",parent)
854 mesh.Scale = Vector3.new(x,y,z)
855 return mesh
856else
857 mesh = Instance.new("SpecialMesh",parent)
858 if meshid ~= "sphere" then
859 if type(meshid) == "number" then mesh.MeshId = "rbxassetid://"..meshid else
860 mesh.MeshId = "rbxassetid://"..meshids[meshid]
861 end
862 else mesh.MeshType = 3 end
863 mesh.Scale = Vector3.new(x,y,z)
864 if meshtexture ~= nil then
865 if type(meshtexture) == "number" then
866 mesh.TextureId = "rbxassetid://"..meshtexture
867 else
868 mesh.TextureId = "rbxassetid://"..textureids[meshtexture] end
869 end
870 return mesh
871 end
872end
873
874function P(x,y,z,color,transparency,cancollide,anchored,parent,typee)
875if typee ~= nil then
876 c = Instance.new("WedgePart",m)
877else
878 c = Instance.new("Part",m)
879end
880c.TopSurface,c.BottomSurface = 0,0
881c.Locked = true
882c.formFactor = "Custom"
883c.Size = Vector3.new(x,y,z)
884if color ~= "random" then
885 c.BrickColor = BrickColor.new(color)
886else
887 c.BrickColor = BrickColor:random()
888end
889c.Transparency = transparency
890c.CanCollide = cancollide
891if anchored ~= nil then
892 c.Anchored = anchored
893end
894if parent ~= nil then
895 c.Parent = parent
896end
897return c
898end
899
900function We(part0,part1,x,y,z,rx,ry,rz,parent)
901w = Instance.new("Motor",m)
902if parent ~= nil then w.Parent = parent end
903 w.Part0,w.Part1 = part0,part1
904 w.C1 = CFrame.new(x,y,z) * CFrame.Angles(rx,ry,rz)
905 return w
906end
907
908
909
910
911function P(x,y,z,color,transparency,cancollide,anchored,parent,typee)
912if typee ~= nil then
913 c = Instance.new("WedgePart",m)
914else
915 c = Instance.new("Part",m)
916end
917c.TopSurface,c.BottomSurface = 0,0
918c.Locked = true
919c.formFactor = "Custom"
920c.Size = Vector3.new(x,y,z)
921if color ~= "random" then
922 c.BrickColor = BrickColor.new(color)
923else
924 c.BrickColor = BrickColor:random()
925end
926c.Transparency = transparency
927c.CanCollide = cancollide
928if anchored ~= nil then
929 c.Anchored = anchored
930end
931if parent ~= nil then
932 c.Parent = parent
933end
934return c
935end
936
937function We(part0,part1,x,y,z,rx,ry,rz,parent)
938w = Instance.new("Motor",m)
939if parent ~= nil then w.Parent = parent end
940 w.Part0,w.Part1 = part0,part1
941 w.C1 = CFrame.new(x,y,z) * CFrame.Angles(rx,ry,rz)
942 return w
943end
944
945function SetAnimation(id,humanoid)
946 if Animating ~= nil then
947 Animating:Stop()
948 end
949 Animate.AnimationId = Asset .. id
950 Animating = humanoid:LoadAnimation(Animate)
951 Animating:Play()
952end
953
954function AnimationStop()
955 unity = false
956 _2_much_power = false
957 some_power = false
958 haha_no = false
959 spin_round = false
960 still_not_that_fast = false
961 tetris_remix = false
962 dat_boi = false
963 memes = false
964 scary_monsters_nice_sprites_remix = false
965 rus = false
966 it_s_already_that_old = false
967 pootis_avi = false
968 buelah_mp3 = false
969 antivirisis = false
970 look_at_this_dude = false
971 if barrelbrick ~= nil then
972 barrelbrick:Remove()
973 barrelbrick = nil
974 end
975 if saxtool ~= nil then
976 saxtool:Remove()
977 saxtool = nil
978 end
979 if sandstorm ~= nil then
980 sandstorm:Remove()
981 sandstorm = nil
982 end
983end
984
985local Musical
986function SetMusic(id,name,volume)
987 Musical = Instance.new("Sound",char.Head)
988 if volume == nil then
989 Musical.Volume = 1
990 else
991 Musical.Volume = volume
992 end
993 Musical.Looped = true
994 Musical.SoundId = Asset .. id
995 Musical.Name=name
996 return Musical
997end
998
999function GenerateGui()
1000 a=Instance.new("ScreenGui")
1001 a.Name = "KrystalDance By KrystalTeam - mlg2 edit by adchand2"
1002 b=Instance.new("ImageLabel",a)
1003 b.BackgroundTransparency = 1
1004 b.Size = UDim2.new(0,250,0,100)
1005 b.Position = UDim2.new(0,0,1,0)
1006 b.Image = Asset .. "269467798"
1007 b.Name = "Logo"
1008 c=Instance.new("TextLabel",b)
1009 c.Size
1010
1011
1012function P(x,y,z,color,transparency,cancollide,anchored,parent,typee)
1013if typee ~= nil then
1014 c = Instance.new("WedgePart",m)
1015else
1016 c = Instance.new("Part",m)
1017end
1018c.TopSurface,c.BottomSurface = 0,0
1019c.Locked = true
1020c.formFactor = "Custom"
1021c.Size = Vector3.new(x,y,z)
1022if color ~= "random" then
1023 c.BrickColor = BrickColor.new(color)
1024else
1025 c.BrickColor = BrickColor:random()
1026end
1027c.Transparency = transparency
1028c.CanCollide = cancollide
1029if anchored ~= nil then
1030 c.Anchored = anchored
1031end
1032if parent ~= nil then
1033 c.Parent = parent
1034end
1035return c
1036end
1037
1038function We(part0,part1,x,y,z,rx,ry,rz,parent)
1039w = Instance.new("Motor",m)
1040if parent ~= nil then w.Parent = parent end
1041 w.Part0,w.Part1 = part0,part1
1042 w.C1 = CFrame.new(x,y,z) * CFrame.Angles(rx,ry,rz)
1043 return w
1044end = UDim2.new(1,0,0,10)
1045 c.BackgroundTransparency = 1
1046 c.Text = "adchand2's MLG edit of:"
1047 c.FontSize = Enum.FontSize.Size11
1048 c.Font = math.random(0,15)
1049 c.TextColor3 = Color3.fromRGB(255,255,255)
1050 --[[b1=Instance.new("TextButton",a)
1051 b1.Text="Change Face"
1052 b1.Style="RobloxRoundButton"
1053 b1.FontSize = Enum.FontSize.Size14
1054 b1.Font = Enum.Font.SourceSansLight
1055 b1.Position = UDim2.new(0.4,0,0,0)
1056 b1.Size = UDim2.new(0,80,0,20)
1057 b2=Instance.new("TextButton",a)
1058 b2.Text="Change Body Colours"
1059 b2.Style="RobloxRoundButton"
1060 b2.FontSize = Enum.FontSize.Size14
1061 b2.Font = Enum.Font.SourceSansLight
1062 b2.Position = UDim2.new(0.4,80,0,0)
1063 b2.Size = UDim2.new(0,120,0,20)
1064 b3=Instance.new("TextButton",a)
1065 b3.Text="BGM ID List"
1066 b3.Style="RobloxRoundButton"
1067 b3.FontSize = Enum.FontSize.Size14
1068 b3.Font = Enum.Font.SourceSansLight
1069 b3.Position = UDim2.new(0.4,200,0,0)
1070 b3.Size = UDim2.new(0,70,0,20)
1071 b4=Instance.new("TextButton",a)
1072 b4.Text="Settings"
1073 b4.Style="RobloxRoundButton"
1074 b4.FontSize = Enum.FontSize.Size14
1075 b4.Font = Enum.Font.SourceSansLight
1076 b4.Position = UDim2.new(0.4,270,0,0)
1077 b4.Size = UDim2.new(0,60,0,20)]]
1078 return a
1079end
1080
1081function Generate(player)
1082char = player.Character
1083Hat1 = P(1,1,1,'Black',0,false,false)
1084Hat2 = P(1,1,1,'Black',0,false,false)
1085wait()
1086a=fm(Hat1,121910245,0.7,0.5,0.7,121947422) a.VertexColor = Vector3.new(1,1,1)
1087b=fm(Hat2,13030731,0.95,0.95,0.95,13030735) b.VertexColor = Vector3.new(1,1,1)
1088wait()
1089if char:FindFirstChild("Head") then
1090 We(Hat1,char.Head,0,0.25,-0.135,0,0,0)
1091 We(Hat2,char.Head,0,0.8,0,0,0,0)
1092 if char.Head:FindFirstChild("face") ~= nil then
1093 face = char.Head:FindFirstChild("face")
1094 face.Texture = "rbxassetid://318401263"
1095 end
1096 c=char.Head:clone()
1097 c.Name = "FalseHead"
1098 c.CanCollide = false
1099 c.Parent = char
1100 We(c,char.Head,0,0,0,0,0,0)
1101 char.Head.Transparency = 1
1102 for i,v in pairs(char:GetChildren()) do
1103 if v.ClassName == "Shirt" or v.ClassName == "Pants" or v.ClassName == "Accessory" or v.ClassName == "CharacterMesh" or v.ClassName == "ShirtGraphic" then
1104 v:Remove()
1105 end
1106 if v.ClassName == "BodyColors" then
1107 v.HeadColor = BrickColor.new("Cool yellow")
1108 v.LeftArmColor = BrickColor.new("Cool yellow")
1109 v.LeftLegColor = BrickColor.new("Bright blue")
1110 v.RightArmColor = BrickColor.new("Cool yellow")
1111 v.RightLegColor = BrickColor.new("Bright blue")
1112 v.TorsoColor = BrickColor.new("Dark green")
1113 end
1114 if v.ClassName == "Part" then
1115 if v.Name == "Head" or v.Name == "FalseHead" then
1116 v.BrickColor = BrickColor.new("Cool yellow")
1117 else
1118 v.BrickColor = BrickColor.new("Cool yellow")
1119 end
1120 end
1121 end
1122----------musics---------------
1123 M1=SetMusic(482893067,"M1") -- some_power, front_page (561274893), nova_fire (168340433) [Q]
1124 M2=SetMusic(408731259,"M2") -- _2_much_power, flow (273029844), harlem_dank (265576262) [E]
1125 M3=SetMusic(257341751,"M3") -- unity, always_lying (421360692), jawn (142523507) [R]
1126 M4=SetMusic(258500169,"M4") -- haha_no, ok_you_re_hearing_some_cancerous_stuff_i_give_up_now (416308003), this_is_epic (151021035) [T]
1127 M5=SetMusic(187013797,"M5") -- spin_round, hard_one (462957432), gta_loud (253539621) [Y]
1128 M6=SetMusic(224705079,"M6") -- still_not_that_fast, ok (385741330), sanic_x (178752763) [U]
1129 M7=SetMusic(200624713,"M7") -- tetris_remix, it_s_low (334046170), mlg_dubbs (340617496) [F]
1130 M8=SetMusic(410806544,"M8") -- dat_boi, ayyyyyyyyyyyyyyyyyyyyyyyy_lmao (400663465), _2204355 (142355221) [P]
1131 M9=SetMusic(242178814,"M9") -- memes, TGG (297802798), mlg_style (362846090) [G]
1132 M10=SetMusic(142375403,"M10") -- scary_monsters_nice_sprites_remix, yeah_bass (410005698), paper_mario (145369820) [H]
1133 M11=SetMusic(542441126,"M11") -- rus, we_rise (427801633), otis (142308159) [J]
1134 M12=SetMusic(501548847,"M12") -- it_s_already_that_old, yeah (277253359), LJN (167373003) [K]
1135 M13=SetMusic(336581561,"M13") -- pootis_avi, it_s_metal (184740384), ITS_NO_USE (130844716) [L]
1136 M14=SetMusic(214285554,"M14") -- buelah_mp3, GOOD_JOB (225074231), spm (202234516)[Z]
1137 M15=SetMusic(278068026,"M15") -- antivirisis, hardness (265479911), stylo (144940679) [X]
1138 M16=SetMusic(424610918,"M16") -- look_at_this_dude, hard_bass (324499479), nedm (138811227) [C]
1139-------------------------------
1140
1141 if char:FindFirstChild("HumanoidRootPart") ~= nil then
1142 rootpart = char:FindFirstChild("HumanoidRootPart")
1143 end
1144 if showtag == true then
1145 local bbg = Instance.new("BillboardGui",c)
1146 bbg.Adornee = c
1147 bbg.Name = "NametagGUI"
1148 bbg.Size = UDim2.new(6,0,1.5,0)
1149 bbg.StudsOffset = Vector3.new(0,2,0)
1150 local fram = Instance.new("ImageLabel",bbg)
1151 fram.Image = Asset.."506843247"
1152 fram.Size = UDim2.new(1,0,1,0)
1153 fram.BackgroundColor3 = Color3.new(0,0,0)
1154 fram.BackgroundTransparency = 1
1155 fram.BorderSizePixel = 0
1156 local box = Instance.new("TextLabel",fram)
1157 box.Size = UDim2.new(1,0,1,0)
1158 box.BackgroundColor = BrickColor.new("White")
1159 box.TextColor3 = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
1160 box.TextStrokeTransparency = 0.5
1161 box.Font = math.random(0,15)
1162 box.Text = Player.Name
1163 box.BackgroundTransparency = 1
1164 box.BorderSizePixel = 0
1165 box.Position = UDim2.new(0,0,0,0)
1166 box.TextScaled = true
1167 end
1168 if char:FindFirstChild("Humanoid") ~= nil then
1169 char:FindFirstChild("Humanoid").MaxHealth = (100*100*100*100)*100
1170 wait()
1171 char:FindFirstChild("Humanoid").Health = char:FindFirstChild("Humanoid").MaxHealth
1172 --char:FindFirstChild("Humanoid").Name = game.Players.LocalPlayer.Name
1173 humanoid = char:FindFirstChild("Humanoid")
1174 if humanoid:FindFirstChild("Animator") ~= nil then
1175 humanoid:FindFirstChild("Animator"):Remove()
1176 --Instance.new("Animator",humanoid)
1177 end
1178 if char:FindFirstChild("Animate") ~= nil then
1179 char:FindFirstChild("Animate"):Remove()
1180 end
1181 end
1182 Mouse = player:GetMouse()
1183 Music = Instance.new("Sound",char.Head)
1184 Music.Volume = 1
1185 Music.Looped = true
1186 Music.SoundId = Asset
1187 Animate = Instance.new("Animation",char.Head)
1188 Animate.AnimationId = Asset
1189
1190
1191 function P(x,y,z,color,transparency,cancollide,anchored,parent,typee)
1192if typee ~= nil then
1193 c = Instance.new("WedgePart",m)
1194else
1195 c = Instance.new("Part",m)
1196end
1197c.TopSurface,c.BottomSurface = 0,0
1198c.Locked = true
1199c.formFactor = "Custom"
1200c.Size = Vector3.new(x,y,z)
1201if color ~= "random" then
1202 c.BrickColor = BrickColor.new(color)
1203else
1204 c.BrickColor = BrickColor:random()
1205end
1206c.Transparency = transparency
1207c.CanCollide = cancollide
1208if anchored ~= nil then
1209 c.Anchored = anchored
1210end
1211if parent ~= nil then
1212 c.Parent = parent
1213end
1214return c
1215end
1216
1217function We(part0,part1,x,y,z,rx,ry,rz,parent)
1218w = Instance.new("Motor",m)
1219if parent ~= nil then w.Parent = parent end
1220 w.Part0,w.Part1 = part0,part1
1221 w.C1 = CFrame.new(x,y,z) * CFrame.Angles(rx,ry,rz)
1222 return w
1223end
1224
1225 head = char:FindFirstChild("Head")
1226 torso = char:FindFirstChild("Torso")
1227 ra = char:findFirstChild("Right Arm")
1228 la = char:findFirstChild("Left Arm")
1229 rl = char:findFirstChild("Right Leg")
1230 ll = char:findFirstChild("Left Leg")
1231 rs = torso:findFirstChild("Right Shoulder")
1232 ls = torso:findFirstChild("Left Shoulder")
1233 rh = torso:findFirstChild("Right Hip")
1234 lh = torso:findFirstChild("Left Hip")
1235 neck = torso:findFirstChild("Neck")
1236 rj = char:findFirstChild("HumanoidRootPart"):findFirstChild("RootJoint")
1237
1238 state = humanoid:GetState()
1239 local ca = nil
1240 ca=GenerateGui()
1241 ca.Parent = player.PlayerGui
1242 if ca:FindFirstChild("Logo") ~= nil then
1243 ca:FindFirstChild("Logo"):TweenPosition(UDim2.new(0, 0, 1, -100), "Out", "Elastic", 3, true)
1244 if ca:FindFirstChild("Intro") ~= nil then
1245 ca:FindFirstChild("Intro"):Play()
1246 coroutine.resume(coroutine.create(function()
1247 for i=0,30 do
1248 ca:FindFirstChild("Intro").Volume = 1/(i/2)
1249 wait(0.5)
1250 if i >= 30 then
1251 break
1252 end
1253 end
1254 end))
1255 end
1256 end
1257
1258 if humanoid ~= nil then
1259 humanoid.Changed:connect(function(pro)
1260 if pro == "MoveDirection" or pro == "Jump" then
1261 if Music.IsPlaying == true then
1262 AnimationStop()
1263 end
1264 end
1265 end)
1266 humanoid.Died:connect(function()
1267 AnimationStop()
1268 end)
1269
1270 Mouse.KeyUp:connect(function(key)
1271 if key == "w" then
1272 W = false
1273 end
1274 if key == "a" then
1275 A = false
1276 end
1277 if key == "s" then
1278 S = false
1279 end
1280 if key == "d" then
1281 D = false
1282 end
1283 if string.byte(key) == 48 then
1284 run = false
1285 end
1286 end)
1287
1288 Mouse.KeyDown:connect(function(key)
1289 if key == "w" then
1290 W = true
1291 AnimationStop()
1292 end
1293 if key == "a" then
1294 A = true
1295 AnimationStop()
1296 end
1297 if key == "s" then
1298 S = true
1299 AnimationStop()
1300 end
1301 if key == "d" then
1302 D = true
1303 AnimationStop()
1304 end
1305 end)
1306
1307
1308
1309 Mouse.KeyDown:connect(function(key)
1310 KeyUsed(key)
1311 end)
1312end
1313end
1314inform2("KrystalDance MLG3 - © 2016-17 adchand2/memesbruh03.")
1315end
1316
1317function inform(var)
1318local bbg = Instance.new("BillboardGui",WorkPlayer.FalseHead)
1319 bbg.Adornee = bbg.Parent
1320 bbg.Name = "Input"
1321 bbg.Size = UDim2.new(6,0,1.5,0)
1322 bbg.StudsOffset = Vector3.new(0,3,0)
1323 local fram = Instance.new("ImageLabel",bbg)
1324 fram.Image = Asset.."506843247"
1325 fram.Size = UDim2.new(1,0,1,0)
1326 fram.BackgroundColor3 = Color3.new(0,0,0)
1327 fram.BackgroundTransparency = 1
1328 fram.BorderSizePixel = 0
1329 local box = Instance.new("TextLabel",fram)
1330 box.Size = UDim2.new(1,0,1,0)
1331 box.BackgroundColor = BrickColor.new("White")
1332 box.TextColor3 = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
1333 box.TextStrokeTransparency = 0.5
1334 box.Font = math.random(0,15)
1335 box.Text = var
1336 box.BackgroundTransparency = 1
1337 box.BorderSizePixel = 0
1338 box.Position = UDim2.new(0,0,0,0)
1339 box.TextScaled = true
1340 while true do
1341 wait(0.01)
1342 fram.Position=fram.Position-UDim2.new(0,0,0,1)
1343 fram.ImageTransparency=fram.ImageTransparency+0.01
1344 box.TextTransparency=box.TextTransparency+0.01
1345 if --[[fram.ImageTransparency==1 and]] box.TextTransparency==1 then
1346 bbg:Destroy()
1347 end
1348 end
1349end
1350
1351function KeyUsed(key)
1352 if humanoid ~= nil then
1353 if humanoid.Health > 0 then
1354 if string.byte(key) == 32 then
1355 jump = true
1356 AnimationStop()
1357 --sit = false
1358 end
1359 if string.byte(key) == 50 then
1360 AnimationStop()
1361 if sit == true then
1362 sit = false
1363 else
1364 sit = true
1365 end
1366 end
1367 if string.byte(key) == 48 then
1368 run = true
1369 end
1370 if W == false and A == false and S == false and D == false and jump == false and sit == false then
1371 if key == "Q" or key == "q" then
1372 AnimationStop()
1373 some_power = true
1374 M1:Play()
1375 if advan == false then
1376 if smode == 1 then
1377 inform2("some_power")
1378 elseif smode == 2 then
1379 inform2("front_page")
1380 elseif smode == 3 then
1381 inform2("nova_fire")
1382 end
1383 if advan == true then
1384 if smode == 1 then
1385 forcheck=482893067
1386 inform2("Variable: some_power")
1387 wait(0.2)
1388 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1389 wait(0.2)
1390 inform2("Original ID: "..forcheck)
1391 elseif smode == 2 then
1392 forcheck=561274893
1393 inform2("Variable: front_page")
1394 wait(0.2)
1395 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1396 wait(0.2)
1397 inform2("Original ID: "..forcheck)
1398 elseif smode == 3 then
1399 forcheck=168340433
1400 inform2("Variable: nova_fire")
1401 wait(0.2)
1402 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1403 wait(0.2)
1404 inform2("Original ID: "..forcheck)
1405 end
1406 end
1407 end
1408 end
1409 if key == "E" or key == "e" then
1410 AnimationStop()
1411 _2_much_power = true
1412 M2:Play()
1413 if advan == false then
1414 if smode == 1 then
1415 inform2("_2_much_power")
1416 elseif smode == 2 then
1417 inform2("flow")
1418 elseif smode == 3 then
1419 inform2("harlem_dank")
1420 end
1421 if advan == true then
1422 if smode == 1 then
1423 forcheck=408731259
1424 inform2("Variable: _2_much_power")
1425 wait(0.2)
1426 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1427 wait(0.2)
1428 inform2("Original ID: "..forcheck)
1429 elseif smode == 2 then
1430 forcheck=273029844
1431 inform2("Variable: flow")
1432 wait(0.2)
1433 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1434 wait(0.2)
1435 inform2("Original ID: "..forcheck)
1436 elseif smode == 3 then
1437 forcheck=265576262
1438 inform2("Variable: harlem_dank")
1439 wait(0.2)
1440 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1441 wait(0.2)
1442 inform2("Original ID: "..forcheck)
1443 end
1444 end
1445 end
1446 end
1447 if key == "R" or key == "r" then
1448 AnimationStop()
1449 unity = true
1450 M3:Play()
1451 if advan == false then
1452 if smode == 1 then
1453 inform2("unity")
1454 elseif smode == 2 then
1455 inform2("always_lying")
1456 elseif smode == 3 then
1457 inform2("jawn")
1458 end
1459 if advan == true then
1460 if smode == 1 then
1461 forcheck=257341751
1462 inform2("Variable: unity")
1463 wait(0.2)
1464 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
1465
1466local files = {
1467["MThemeManager.ti"]="--[[\
1468 The MThemeManager mixin \"should\" be used by classes that want to manage objects which are themeable, the main example being the 'Application' class.\
1469]]\
1470\
1471local function deepCopy( source )\
1472 if type( source ) == \"table\" then\
1473 local copy = {}\
1474 for key, value in next, source, nil do copy[ deepCopy( key ) ] = deepCopy( value ) end\
1475\
1476 return copy\
1477 end\
1478\
1479 return source\
1480end\
1481\
1482class \"MThemeManager\" abstract() {\
1483 themes = {}\
1484}\
1485\
1486--[[\
1487 @instance\
1488 @desc Adds the given theme into this objects `themes` table\
1489 @param <Theme Instance - theme>\
1490]]\
1491function MThemeManager:addTheme( theme )\
1492 self:removeTheme( theme )\
1493 table.insert( self.themes, theme )\
1494\
1495 self:update()\
1496end\
1497\
1498--[[\
1499 @instance\
1500 @desc Removes the given theme from this objects `themes` table. Returns true if a theme was removed, false otherwise.\
1501 @param <Instance 'Theme'/string name - target>\
1502 @return <boolean - success>\
1503]]\
1504function MThemeManager:removeTheme( target )\
1505 local searchName = ( type( target ) == \"string\" and true ) or ( not Titanium.typeOf( target, \"Theme\", true ) and error \"Invalid target to remove\" )\
1506 local themes = self.themes\
1507 for i = 1, #themes do\
1508 if ( searchName and themes[ i ].name == target ) or ( not searchName and themes[ i ] == target ) then\
1509 table.remove( themes, i )\
1510 self:update()\
1511\
1512 return true\
1513 end\
1514 end\
1515end\
1516\
1517--[[\
1518 @instance\
1519 @desc Adds a theme instance named 'name' and imports the file contents from 'location' to this object\
1520 @param <string - name>, <string - location>\
1521]]\
1522function MThemeManager:importTheme( name, location )\
1523 self:addTheme( Theme.fromFile( name, location ) )\
1524end\
1525\
1526--[[\
1527 @instance\
1528 @desc Updates the theme information bound to this object. All nodes under this parent are reset and the rules are reapplied to each.\
1529 'onThemeUpdate' is called on each child node allowing for each node to update themselves after their new theme information has been applied.\
1530 @param [table - target]\
1531]]\
1532function MThemeManager:update( target )\
1533 self:cacheAllApplicableRules()\
1534\
1535 local target = target or self.collatedNodes\
1536 for i = 1, #target do target[ i ]:onThemeUpdate() end\
1537end\
1538\
1539--[[\
1540 @instance\
1541 @desc Resets the applicableRules table on all nodes of type 'type' that are under this node (collated/query)\
1542 @param <string - type>\
1543]]\
1544function MThemeManager:resetApplicableRules( type )\
1545 local nodes = type == \"*\" and self.collatedNodes or self:query( type ).result\
1546 for i = 1, #nodes do\
1547 nodes[ i ].applicableRules = {}\
1548 end\
1549end\
1550\
1551--[[\
1552 @instance\
1553 @desc Iterates over the rules given and applies them as 'applicable rules' to each eligible node (collated/query).\
1554 These 'applicable rules' are then used by the node to determine theme properties.\
1555 @param <table - rules>\
1556]]\
1557function MThemeManager:cacheApplicableRules( rules )\
1558 local cachedRegistry, cachedTypes, rule, compute = {}, {}\
1559\
1560 for i = 1, #rules do\
1561 rule = rules[ i ]\
1562 compute = rule.computeType\
1563\
1564 self:query( rule.query ):each(function( item )\
1565 local applicable = item.applicableRules\
1566 if compute then\
1567 local itemType = item.__type\
1568 if not cachedRegistry[ itemType ] then\
1569 cachedRegistry[ itemType ] = Titanium.getClass( itemType ).getRegistry()\
1570 end\
1571\
1572 local reg = cachedRegistry[ itemType ]\
1573 if not cachedTypes[ itemType ] then\
1574 cachedTypes[ itemType ] = reg.constructor and reg.constructor.argumentTypes or {}\
1575 end\
1576\
1577 local ruleClone = deepCopy( rule )\
1578 ruleClone.value = XMLParser.convertArgType( ruleClone.value, cachedTypes[ itemType ][ reg.alias[ rule.property ] or rule.property ] )\
1579 applicable[ #applicable + 1 ] = ruleClone\
1580 else\
1581 applicable[ #applicable + 1 ] = rule\
1582 end\
1583 end)\
1584 end\
1585end\
1586\
1587--[[\
1588 @instance\
1589 @desc Iterates over each theme bound to this object and caches the rules for type 'type' by passing them to 'MThemeManager.cacheApplicableRules'\
1590 @param <string - type>, [boolean - manualReset]\
1591]]\
1592function MThemeManager:cacheApplicableRulesForType( type, manualReset )\
1593 local themes = self.themes\
1594 if not manualReset then self:resetApplicableRules( type ) end\
1595\
1596 for i = 1, #themes do\
1597 self:cacheApplicableRules( themes[ i ].rules[ type ] or {} )\
1598\
1599 local ANY = themes[ i ].rules.ANY\
1600 if ANY then self:cacheApplicableRules( ANY ) end\
1601 end\
1602end\
1603\
1604--[[\
1605 @instance\
1606 @desc Caches all rules from all themes bound to this object by passing them to 'MThemeManager.cacheApplicableRules'\
1607 @param [boolean - manualReset]\
1608]]\
1609function MThemeManager:cacheAllApplicableRules( manualReset )\
1610 local themes, rules = self.themes\
1611 if not manualReset then self:resetApplicableRules \"*\" end\
1612\
1613 for i = 1, #themes do\
1614 rules = themes[ i ].rules\
1615 for type in pairs( rules ) do\
1616 self:cacheApplicableRules( rules[ type ] )\
1617 end\
1618 end\
1619end\
1620",
1621["QueryParser.ti"]="local function parseValue( val )\
1622 if val == \"true\" then return true\
1623 elseif val == \"false\" then return false end\
1624\
1625 return tonumber( val ) or error(\"Invalid value passed for parsing '\"..tostring( val )..\"'\")\
1626end\
1627\
1628class \"QueryParser\" extends \"Parser\"\
1629\
1630function QueryParser:__init__( queryString )\
1631 self:super( QueryLexer( queryString ).tokens )\
1632end\
1633\
1634function QueryParser:parse()\
1635 local allQueries, currentQuery, currentStep = {}, {}, {}\
1636\
1637 local nextStepDirect\
1638 local function advanceSection()\
1639 if next( currentStep ) then\
1640 table.insert( currentQuery, currentStep )\
1641 currentStep = { direct = nextStepDirect }\
1642\
1643 nextStepDirect = nil\
1644 end\
1645 end\
1646\
1647 local token = self:stepForward()\
1648 while token do\
1649 if token.type == \"QUERY_TYPE\" then\
1650 if currentStep.type then self:throw( \"Attempted to set query type to '\"..token.value..\"' when already set as '\"..currentStep.type..\"'\" ) end\
1651\
1652 currentStep.type = token.value\
1653 elseif token.type == \"QUERY_CLASS\" then\
1654 if not currentStep.classes then currentStep.classes = {} end\
1655\
1656 table.insert( currentStep.classes, token.value )\
1657 elseif token.type == \"QUERY_ID\" then\
1658 if currentStep.id then self:throw( \"Attempted to set query id to '\"..token.value..\"' when already set as '\"..currentStep.id..\"'\" ) end\
1659\
1660 currentStep.id = token.value\
1661 elseif token.type == \"QUERY_SEPERATOR\" then\
1662 if self.tokens[ self.position + 1 ].type ~= \"QUERY_DIRECT_PREFIX\" then\
1663 advanceSection()\
1664 end\
1665 elseif token.type == \"QUERY_END\" then\
1666 advanceSection()\
1667\
1668 if next( currentQuery ) then\
1669 table.insert( allQueries, currentQuery )\
1670 currentQuery = {}\
1671 else\
1672 self:throw( \"Unexpected '\"..token.value..\"' found, no left hand query\" )\
1673 end\
1674 elseif token.type == \"QUERY_COND_OPEN\" then\
1675 currentStep.condition = self:parseCondition()\
1676 elseif token.type == \"QUERY_DIRECT_PREFIX\" and not nextStepDirect then\
1677 nextStepDirect = true\
1678 else\
1679 self:throw( \"Unexpected '\"..token.value..\"' found while parsing query\" )\
1680 end\
1681\
1682 token = self:stepForward()\
1683 end\
1684\
1685 advanceSection()\
1686 if next( currentQuery ) then\
1687 table.insert( allQueries, currentQuery )\
1688 end\
1689\
1690 self.query = allQueries\
1691end\
1692\
1693function QueryParser:parseCondition()\
1694 local conditions, condition = {}, {}\
1695\
1696 local token = self:stepForward()\
1697 while true do\
1698 if token.type == \"QUERY_COND_ENTITY\" and ( condition.symbol or not condition.property ) then\
1699 condition[ condition.symbol and \"value\" or \"property\" ] = condition.symbol and parseValue( token.value ) or token.value\
1700 elseif token.type == \"QUERY_COND_STRING_ENTITY\" and condition.symbol then\
1701 condition.value = token.value\
1702 elseif token.type == \"QUERY_COND_SYMBOL\" and not condition.property and token.value == \"#\" then\
1703 condition.modifier = token.value\
1704 elseif token.type == \"QUERY_COND_SYMBOL\" and ( condition.property ) then\
1705 condition.symbol = token.value\
1706 elseif token.type == \"QUERY_COND_SEPERATOR\" and next( condition ) then\
1707 conditions[ #conditions + 1 ] = condition\
1708 condition = {}\
1709 elseif token.type == \"QUERY_COND_CLOSE\" and ( not condition.property or ( condition.property and condition.value ) ) then\
1710 break\
1711 else\
1712 self:throw( \"Unexpected '\"..token.value..\"' inside of condition block\" )\
1713 end\
1714\
1715 token = self:stepForward()\
1716 end\
1717\
1718 if next( condition ) then\
1719 conditions[ #conditions + 1 ] = condition\
1720 end\
1721\
1722 return #conditions > 0 and conditions or nil\
1723end\
1724",
1725["Theme.ti"]="--[[\
1726 The Theme class \"is\" a basic class \"designed\" to hold styling rules.\
1727\
1728 Themes are added to objects using the MThemeManager mixin (or a custom implementation). These themes then dictate the appearance of objects that utilize 'MThemeable'.\
1729]]\
1730local function getTagDetails( rule )\
1731 return ( rule.arguments.id and ( \"#\" .. rule.arguments.id ) or \"\" ) .. (function( classString ) local classes = \"\"; for className in classString:gmatch(\"%S+\") do classes = classes .. \".\"..className end; return classes end)( rule.arguments[\"class\"] or \"\" )\
1732end\
1733\
1734local function splitXMLTheme( queue, tree )\
1735 for i = 1, #tree do\
1736 local children = tree[ i ].children\
1737 if children then\
1738 for c = 1, #children do\
1739 local type = tree[ i ].type\
1740 queue[ #queue + 1 ] = { ( type == \"Any\" and \"*\" or type ) .. getTagDetails( tree[ i ] ), children[ c ], tree[ i ] }\
1741 end\
1742 end\
1743 end\
1744\
1745 return queue\
1746end\
1747\
1748class \"Theme\" {\
1749 name = false;\
1750\
1751 rules = {};\
1752}\
1753\
1754--[[\
1755 @constructor\
1756 @desc Constructs the Theme by setting the name.\
1757 @param <string - name>, [string - source]\
1758]]\
1759function Theme:__init__( name, source )\
1760 self.name = type( name ) == \"string\" and name or error(\"Failed to initialise Theme. Name '\"..tostring( name )..\"' is invalid, expected string.\")\
1761\
1762 if source then self.rules = Theme.parse( source ) end\
1763end\
1764\
1765--[[\
1766 @static\
1767 @desc Parses XML source code by lexing/parsing it into an XML tree. The XML is then parsed into theme rules\
1768 @param <string - source>\
1769 @return <table - rules>\
1770]]\
1771function Theme.static.parse( source )\
1772 local queue, rawRules, q = splitXMLTheme( {}, XMLParser( source ).tree ), {}, 1\
1773\
1774 local function processQueueEntry( entry )\
1775 local queryPrefix, rule = entry[ 1 ], entry[ 2 ]\
1776 local children = rule.children\
1777\
1778 if children then\
1779 for c = 1, #children do\
1780 if not Titanium.getClass( rule.type ) and rule.type ~= \"Any\" then\
1781 return error( \"Failed to generate theme data. Child target '\"..rule.type..\"' doesn't exist as a Titanium class\" )\
1782 end\
1783\
1784 local type = rule.type\
1785 queue[ #queue + 1 ] = { queryPrefix .. \" \" .. ( rule.arguments.direct and \"> \" or \"\" ) .. ( type == \"Any\" and \"*\" or type ) .. getTagDetails( rule ), children[ c ], rule }\
1786 end\
1787 elseif rule.content then\
1788 local ownerType = entry[ 3 ].type\
1789 local dynamic = rule.arguments.dynamic\
1790\
1791 local ruleTarget, computeType, value = ownerType, false, rule.content\
1792 if ownerType == \"Any\" then\
1793 ruleTarget, computeType = \"ANY\", true\
1794 elseif not dynamic then\
1795 local parentReg = Titanium.getClass( ownerType ).getRegistry()\
1796 local argumentTypes = parentReg.constructor and parentReg.constructor.argumentTypes or {}\
1797\
1798 value = XMLParser.convertArgType( value, argumentTypes[ parentReg.alias[ rule.type ] or rule.type ] )\
1799 end\
1800\
1801 if dynamic then\
1802 value = DynamicEqParser( rule.content )\
1803 end\
1804\
1805 if not rawRules[ ruleTarget ] then rawRules[ ruleTarget ] = {} end\
1806 table.insert( rawRules[ ruleTarget ], {\
1807 query = queryPrefix,\
1808 computeType = not dynamic and computeType or nil,\
1809 property = rule.type,\
1810 value = value,\
1811 important = rule.arguments.important,\
1812 isDynamic = dynamic\
1813 })\
1814 else\
1815 return error( \"Failed to generate theme data. Invalid theme rule found. No value (XML_CONTENT) has been set for tag '\"..rule.type..\"'\" )\
1816 end\
1817 end\
1818\
1819 while q <= #queue do\
1820 processQueueEntry( queue[ q ] )\
1821 q = q + 1\
1822 end\
1823\
1824 return rawRules\
1825end\
1826\
1827--[[\
1828 @static\
1829 @desc Creates a Theme instance with the name passed and the source as the contents of the file at 'path'.\
1830 @param <string - name>, <string - path>\
1831 @return <Theme Instance - Theme>\
1832]]\
1833function Theme.static.fromFile( name, path )\
1834 if not fs.exists( path ) then\
1835 return error( \"Path '\"..tostring( path )..\"' cannot be found\" )\
1836 end\
1837\
1838 local h = fs.open( path, \"r\" )\
1839 local content = h.readAll()\
1840 h.close()\
1841\
1842 return Theme( name, content )\
1843end\
1844",
1845["Pane.ti"]="--[[\
1846 A pane is a very simple node that simply draws a box at 'X', 'Y' with dimensions 'width', 'height'.\
1847]]\
1848\
1849class \"Pane\" extends \"Node\" {\
1850 backgroundColour = colours.black;\
1851\
1852 allowMouse = true;\
1853 useAnyCallbacks = true;\
1854}\
1855\
1856--[[\
1857 @instance\
1858 @desc Resolves arguments and calls super constructor.\
1859]]\
1860function Pane:__init__( ... )\
1861 self:resolve( ... )\
1862 self:super()\
1863end\
1864\
1865--[[\
1866 @instance\
1867 @desc Clears the canvas, the canvas background colour becomes 'backgroundColour' during the clear.\
1868 @param [boolean - force]\
1869]]\
1870function Pane:draw( force )\
1871 local raw = self.raw\
1872 if raw.changed or force then\
1873 raw.canvas:clear()\
1874 raw.changed = false\
1875 end\
1876end\
1877\
1878--[[\
1879 @instance\
1880 @desc Handles any mouse events cast onto this node to prevent nodes under it being affected by them.\
1881 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
1882]]\
1883function Pane:onMouse( event, handled, within )\
1884 if not within or handled then return end\
1885\
1886 event.handled = true\
1887end\
1888\
1889configureConstructor({\
1890 orderedArguments = {\"X\", \"Y\", \"width\", \"height\", \"backgroundColour\"}\
1891}, true)\
1892",
1893["DynamicEqParser.ti"]="local TERMS = { \"NAME\", \"STRING\", \"NUMBER\", \"PAREN\" }\
1894local BIN_AMBIG = { \"binary\", \"ambiguos\" }\
1895local UNA_AMBIG = { \"unary\", \"ambiguos\" }\
1896\
1897class \"DynamicEqParser\" extends \"Parser\" {\
1898 state = \"root\";\
1899 stacks = {{}};\
1900 output = \"local args = ...; return \";\
1901}\
1902\
1903function DynamicEqParser:__init__( expression )\
1904 self:super( DynamicEqLexer( expression ).tokens )\
1905end\
1906\
1907function DynamicEqParser:testForOperator( beforeType, afterType, optional, beforeOffset, afterOffset )\
1908 local pass, before, after = self:testAdjacent( beforeType and \"OPERATOR\", afterType and \"OPERATOR\", false, beforeOffset, afterOffset, not optional )\
1909 if not pass then return false end\
1910\
1911 local function test( token, filter )\
1912 if not token then return true elseif not filter then return false end\
1913 if type( filter ) == \"table\" then\
1914 for i = 1, #filter do\
1915 if token[ filter[ i ] ] or filter[ i ] == \"*\" then return true end\
1916 end\
1917 else\
1918 if type == \"*\" then return true end\
1919 return token[ filter ]\
1920 end\
1921 end\
1922\
1923 local bT, aT = test( before, beforeType ), test( after, afterType )\
1924 if beforeType and afterType then return bT and aT else return ( beforeType and bT ) or ( afterType and aT ) end\
1925end\
1926\
1927function DynamicEqParser:testForTerms( pre, post, optional )\
1928 return self:testAdjacent( pre and TERMS, post and TERMS, false, false, false, not optional )\
1929end\
1930\
1931function DynamicEqParser:resolveStacks( target )\
1932 local stacks, instances = self.stacks, {}\
1933 for i = 1, #stacks - ( #stacks[ #stacks ] == 0 and 1 or 0 ) do\
1934 local stack = stacks[ i ]\
1935 if #stack <= 1 then\
1936 self:throw(\"Invalid stack '\".. stack[ 1 ] ..\"'. At least 2 parts must exist to resolve\")\
1937 end\
1938\
1939 local stackStart, instancePoint = stack[ 1 ]\
1940 if stackStart == \"self\" then\
1941 instancePoint = target\
1942 elseif stackStart == \"parent\" then\
1943 instancePoint = target.parent\
1944 elseif stackStart == \"application\" then\
1945 instancePoint = target.application\
1946 else self:throw(\"Invalid stack start '\"..stackStart..\"'. Only self, parent and application allowed\") end\
1947\
1948 for p = 2, #stack - 1 do\
1949 if not instancePoint then self:throw(\"Failed to resolve stacks. Index '\"..stack[ p ]..\"' could not be accessed on '\"..tostring( instancePoint )..\"'\") end\
1950 instancePoint = instancePoint[ stack[ p ] ]\
1951 end\
1952\
1953 if not instancePoint then self:throw \"Invalid instance\" elseif not stack[ #stack ] then self:throw \"Invalid property\" end\
1954 instances[ #instances + 1 ] = { stack[ #stack ], instancePoint }\
1955 end\
1956\
1957 return instances\
1958end\
1959\
1960function DynamicEqParser:appendToOutput( str )\
1961 self.output = self.output .. ( str or self:getCurrentToken().value )\
1962end\
1963\
1964function DynamicEqParser:parseRootState( token )\
1965 token = token or self:getCurrentToken()\
1966 if token.type == \"NAME\" then\
1967 local filter = { \"OPERATOR\", \"DOT\", \"PAREN\" }\
1968 if not self:testAdjacent( filter, filter ) then self:throw(\"Unexpected name '\"..token.value..\"'\") end\
1969\
1970 self:appendToStack( token.value )\
1971 self:setState \"name\"\
1972\
1973 self:appendToOutput( \"args[\"..#self.stacks..\"]\" )\
1974 elseif token.type == \"PAREN\" then\
1975 if token.value == \"(\" then\
1976 if not ( self:testForOperator( BIN_AMBIG, false, true ) and ( self:testForTerms( false, true ) or self:testForOperator( false, UNA_AMBIG ) ) ) then\
1977 self:throw(\"Unexpected parentheses '\"..token.value..\"'\")\
1978 end\
1979 elseif token.value == \")\" then\
1980 if not ( self:testForTerms( true ) and self:testForOperator( false, BIN_AMBIG, true ) ) then\
1981 self:throw(\"Unexpected parentheses '\"..token.value..\"'\")\
1982 end\
1983 else self:throw(\"Invalid parentheses '\"..token.value..\"'\") end\
1984\
1985 self:appendToOutput()\
1986 elseif token.type == \"STRING\" then\
1987 local unaryOffset = self:testForOperator \"unary\" and 1 or 0\
1988 if not ( ( self:testForOperator( BIN_AMBIG, false, false, unaryOffset ) or self:testAdjacent( \"PAREN\", false, false, unaryOffset ) ) and ( self:testForOperator( false, BIN_AMBIG, true ) or self:testAdjacent( false, \"PAREN\" ) ) ) then\
1989 self:throw(\"Unexpected string '\"..token.value..\"'\")\
1990 end\
1991\
1992 self:appendToOutput( (\"%s%s%s\"):format( token.surroundedBy, token.value, token.surroundedBy ) )\
1993 elseif token.type == \"NUMBER\" then\
1994 if not self:testAdjacent( { \"OPERATOR\", \"PAREN\" }, { \"OPERATOR\", \"PAREN\" }, false, false, false ) then\
1995 self:throw(\"Unexpected number '\"..token.value..\"'\")\
1996 end\
1997\
1998 self:appendToOutput()\
1999 elseif token.type == \"OPERATOR\" then\
2000 if token.unary then\
2001 if not ( self:testForTerms( false, true ) and ( self:testForOperator( BIN_AMBIG ) or self:testAdjacent \"PAREN\" ) ) then\
2002 self:throw(\"Unexpected unary operator '\"..token.value..\"'. Operator must follow a binary operator and precede a term\")\
2003 end\
2004 elseif token.binary then\
2005 if not ( self:testForTerms( true ) and ( self:testForOperator( false, \"unary\" ) or self:testForTerms( false, true ) ) ) then\
2006 self:throw(\"Unexpected binary operator '\"..token.value..\"'. Expected terms before and after operator, or unary operator following\")\
2007 end\
2008 elseif token.ambiguos then\
2009 local trailing = self:testForTerms( false, true )\
2010\
2011 if not ( ( ( trailing or ( self:testForOperator( false, UNA_AMBIG ) and self:testForTerms( true ) ) ) and self:testForTerms( true, false, true ) ) or ( self:testForOperator( BIN_AMBIG ) and trailing ) ) then\
2012 self:throw(\"Unexpected ambiguos operator '\"..token.value..\"'\")\
2013 end\
2014 else self:throw(\"Unknown operator '\"..token.value..\"'\") end\
2015\
2016 self:appendToOutput( (\" %s \"):format( token.value ) )\
2017 else\
2018 self:throw(\"Unexpected block '\"..token.value..\"' of token type '\"..token.type..\"'.\")\
2019 end\
2020end\
2021\
2022function DynamicEqParser:parseNameState( token )\
2023 token = token or self:getCurrentToken()\
2024 if token.type == \"DOT\" then\
2025 local trailing = self:peek()\
2026 if trailing and trailing.type == \"NAME\" then\
2027 self:stepForward()\
2028 self:appendToStack( trailing.value )\
2029 else\
2030 local last = self:getStack()\
2031 self:throw(\"Failed to index '\" .. table.concat( last, \".\" ) .. \"'. No name following dot.\")\
2032 end\
2033 else\
2034 self:setState \"root\"\
2035 table.insert( self.stacks, {} )\
2036\
2037 self:parseRootState( token )\
2038 end\
2039end\
2040\
2041function DynamicEqParser:getStack( offset )\
2042 return self.stacks[ #self.stacks + ( offset or 0 ) ]\
2043end\
2044\
2045function DynamicEqParser:appendToStack( value, stackOffset )\
2046 table.insert( self:getStack( stackOffset ), value )\
2047end\
2048\
2049function DynamicEqParser:setState( state )\
2050 self.state = state\
2051end\
2052\
2053function DynamicEqParser:parse()\
2054 local token = self:stepForward()\
2055 while token do\
2056 if self.state == \"root\" then\
2057 self:parseRootState()\
2058 elseif self.state == \"name\" then\
2059 self:parseNameState()\
2060 else\
2061 self:throw(\"Invalid parser state '\"..self.state..\"'\")\
2062 end\
2063\
2064 token = self:stepForward()\
2065 end\
2066end\
2067",
2068["MNodeContainer.ti"]="local function resetNode( self, node )\
2069 node:queueAreaReset()\
2070\
2071 node.parent = nil\
2072 node.application = nil\
2073\
2074 if self.focusedNode == node then\
2075 node.focused = false\
2076 end\
2077\
2078 node:executeCallbacks \"remove\"\
2079\
2080 self.changed = true\
2081 self:clearCollatedNodes()\
2082end\
2083\
2084class \"MNodeContainer\" abstract() {\
2085 nodes = {}\
2086}\
2087\
2088--[[\
2089 @instance\
2090 @desc Adds a node to the object. This node will have its object and parent (this) set\
2091 @param <Instance 'Node' - node>\
2092 @return 'param1 (node)'\
2093]]\
2094function MNodeContainer:addNode( node )\
2095 if not Titanium.typeOf( node, \"Node\", true ) then\
2096 return error( \"Cannot add '\"..tostring( node )..\"' as Node on '\"..tostring( self )..\"'\" )\
2097 end\
2098\
2099 node.parent = self\
2100 if Titanium.typeOf( self, \"Application\", true ) then\
2101 node.application = self\
2102 self.needsThemeUpdate = true\
2103 else\
2104 if Titanium.typeOf( self.application, \"Application\", true ) then\
2105 node.application = self.application\
2106 self.application.needsThemeUpdate = true\
2107 end\
2108 end\
2109\
2110 self.changed = true\
2111 self:clearCollatedNodes()\
2112\
2113 table.insert( self.nodes, node )\
2114 node:updateProperties()\
2115\
2116 if node.focused then node:focus() end\
2117 return node\
2118end\
2119\
2120--[[\
2121 @instance\
2122 @desc Removes a node matching the name* provided OR, if a node object is passed the actual node. Returns false if not found or (true and node)\
2123 @param <Instance 'Node'/string name - target>\
2124 @return <boolean - success>, [node - removedNode**]\
2125\
2126 *Note: In order for the node to be removed its 'name' field must match the 'name' parameter.\
2127 **Note: Removed node will only be returned if a node was removed (and thus success 'true')\
2128]]\
2129function MNodeContainer:removeNode( target )\
2130 local searchName = type( target ) == \"string\"\
2131\
2132 if not searchName and not Titanium.typeOf( target, \"Node\", true ) then\
2133 return error( \"Cannot perform search for node using target '\"..tostring( target )..\"' to remove.\" )\
2134 end\
2135\
2136 local nodes, node, nodeName = self.nodes, nil\
2137 for i = 1, #nodes do\
2138 node = nodes[ i ]\
2139\
2140 if ( searchName and node.id == target ) or ( not searchName and node == target ) then\
2141 resetNode( self, node )\
2142\
2143 table.remove( nodes, i )\
2144 return true, node\
2145 end\
2146 end\
2147\
2148 return false\
2149end\
2150\
2151function MNodeContainer:clearNodes()\
2152 local nodes = self.nodes\
2153 for i = #nodes, 1, -1 do\
2154 resetNode( self, nodes[ i ] )\
2155 table.remove( nodes, i )\
2156 end\
2157end\
2158\
2159--[[\
2160 @instance\
2161 @desc Searches for (and returns) a node with the 'id' specified. If 'recursive' is true and a node that contains others is found, the node will also be searched.\
2162 @param <string - id>, [boolean - recursive]\
2163 @return [Node Instance - node]\
2164]]\
2165function MNodeContainer:getNode( id, recursive )\
2166 local nodes, node = recursive and self.collatedNodes or self.nodes\
2167\
2168 for i = 1, #nodes do\
2169 node = nodes[ i ]\
2170 if node.id == id then\
2171 return node\
2172 end\
2173 end\
2174end\
2175\
2176--[[\
2177 @instance\
2178 @desc Returns true if the mouse event passed is in bounds of a visible child node\
2179 @param <MouseEvent - event>\
2180 @return [boolean - insideBounds]\
2181]]\
2182function MNodeContainer:isMouseColliding( event )\
2183 local eX, eY, nodes = event.X - self.X + 1, event.Y - self.Y + 1, self.nodes\
2184 for i = 1, #nodes do\
2185 local node = nodes[ i ]\
2186 local nodeX, nodeY = node.X, node.Y\
2187\
2188 if node.visible and eX >= nodeX and eX <= nodeX + node.width - 1 and eY >= nodeY and eY <= nodeY + node.height - 1 then\
2189 return true\
2190 end\
2191 end\
2192\
2193 return false\
2194end\
2195\
2196--[[\
2197 @instance\
2198 @desc Returns a 'NodeQuery' instance containing the nodes that matched the query and methods to manipulate\
2199 @param <string - query>\
2200 @return <NodeQuery Instance - Query Result>\
2201]]\
2202function MNodeContainer:query( query )\
2203 return NodeQuery( self, query )\
2204end\
2205\
2206--[[\
2207 @instance\
2208 @desc Clears the collatedNodes of all parents forcing them to update their collatedNodes cache on next retrieval\
2209]]\
2210function MNodeContainer:clearCollatedNodes()\
2211 self.collatedNodes = false\
2212\
2213 local parent = self.parent\
2214 if parent then\
2215 parent:clearCollatedNodes()\
2216 end\
2217end\
2218\
2219function MNodeContainer:getCollatedNodes()\
2220 if not self.collatedNodes or #self.collatedNodes == 0 then\
2221 self:collate()\
2222 end\
2223\
2224 return self.collatedNodes\
2225end\
2226\
2227--[[\
2228 @instance\
2229 @desc Caches all nodes under this container (and child containers) in 'collatedNodes'.\
2230 This list maybe out of date if 'collate' isn't called before usage. Caching is not automatic.\
2231 @param [table - collated]\
2232]]\
2233function MNodeContainer:collate( collated )\
2234 local collated = collated or {}\
2235\
2236 local nodes, node = self.nodes\
2237 for i = 1, #nodes do\
2238 node = nodes[ i ]\
2239 collated[ #collated + 1 ] = node\
2240\
2241 local collatedNode = node.collatedNodes\
2242 if collatedNode then\
2243 for i = 1, #collatedNode do\
2244 collated[ #collated + 1 ] = collatedNode[ i ]\
2245 end\
2246 end\
2247 end\
2248\
2249 self.collatedNodes = collated\
2250end\
2251\
2252--[[\
2253 @instance\
2254 @desc Sets the enabled property of the node to 'enabled'. Sets node's 'changed' to true.\
2255 @param <boolean - enabled>\
2256]]\
2257function MNodeContainer:setEnabled( enabled )\
2258 self.super:setEnabled( enabled )\
2259 if self.parentEnabled then\
2260 local nodes = self.nodes\
2261 for i = 1, #nodes do\
2262 nodes[ i ].parentEnabled = enabled\
2263 end\
2264 end\
2265end\
2266\
2267function MNodeContainer:setParentEnabled( enabled )\
2268 self.super:setParentEnabled( enabled )\
2269\
2270 local newEnabled, nodes = self.enabled, self.nodes\
2271 for i = 1, #nodes do\
2272 nodes[ i ].parentEnabled = newEnabled\
2273 end\
2274end\
2275\
2276\
2277--[[\
2278 @instance\
2279 @desc Iterates over child nodes to ensure that nodes added to this container prior to Application set are updated (with the new Application)\
2280 @param <Application - app>\
2281]]\
2282function MNodeContainer:setApplication( app )\
2283 self.application = app\
2284\
2285 local nodes = self.nodes\
2286 for i = 1, #nodes do\
2287 nodes[ i ].application = app\
2288 end\
2289end\
2290\
2291--[[\
2292 @instance\
2293 @desc Clears the area provided and queues a redraw for child nodes intersecting the area.\
2294 The content of the child node will not be update, it's content will only be drawn to it's parent.\
2295 @param <number - x>, <number - y>, <number - width>, <number - height>\
2296]]\
2297function MNodeContainer:redrawArea( x, y, width, height, xOffset, yOffset )\
2298 if not self.canvas then return end\
2299 self.canvas:clearArea( x, y, width, height )\
2300\
2301 local nodes, node, nodeX, nodeY = self.nodes\
2302 for i = 1, #nodes do\
2303 node = nodes[ i ]\
2304 nodeX, nodeY = node.X + ( xOffset or 0 ), node.Y + ( yOffset or 0 )\
2305\
2306 if not ( nodeX + node.width - 1 < x or nodeX > x + width or nodeY + node.height - 1 < y or nodeY > y + height ) then\
2307 node.needsRedraw = true\
2308 end\
2309 end\
2310\
2311 local parent = self.parent\
2312 if parent then\
2313 parent:redrawArea( self.X + x - 1, self.Y + y - 1, width, height )\
2314 end\
2315end\
2316\
2317--[[\
2318 @instance\
2319 @desc Appends nodes loaded via TML to the Applications nodes.\
2320 @param <string - path>\
2321]]\
2322function MNodeContainer:importFromTML( path )\
2323 TML.fromFile( self, path )\
2324 self.changed = true\
2325end\
2326\
2327--[[\
2328 @instance\
2329 @desc Removes all nodes from the Application and inserts those loaded via TML\
2330 @param <string - path>\
2331]]\
2332function MNodeContainer:replaceWithTML( path )\
2333 local nodes, node = self.nodes\
2334 for i = #nodes, 1, -1 do\
2335 node = nodes[ i ]\
2336 node.parent = nil\
2337 node.application = nil\
2338\
2339 table.remove( nodes, i )\
2340 end\
2341\
2342 self:importFromTML( path )\
2343end\
2344",
2345["KeyEvent.ti"]="class \"KeyEvent\" extends \"Event\" {\
2346 main = \"KEY\";\
2347\
2348 sub = false;\
2349\
2350 keyCode = false;\
2351 keyName = false;\
2352}\
2353\
2354function KeyEvent:__init__( name, key, held, sub )\
2355 self.name = name\
2356 self.sub = sub or name == \"key_up\" and \"UP\" or \"DOWN\"\
2357 self.held = held\
2358\
2359 self.keyCode = key\
2360 self.keyName = keys.getName( key )\
2361\
2362 self.data = { name, key, held }\
2363end\
2364",
2365["MKeyHandler.ti"]="--[[\
2366 The key handler mixin \"facilitates\" common features of objects that utilize key events. The mixin \"can\" manage hotkeys and will check them for validity\
2367 when a key event is caught.\
2368]]\
2369\
2370class \"MKeyHandler\" abstract() {\
2371 static = {\
2372 keyAlias = {}\
2373 };\
2374\
2375 keys = {};\
2376 hotkeys = {};\
2377 cooldown = false;\
2378}\
2379\
2380--[[\
2381 @instance\
2382 @desc 'Handles' a key by updating its status in 'keys'. If the event was a key down, it's status will be set to false if not held and true if it is.\
2383 If the event is a key down, the key's status will be set to nil (use this to detect if a key is not pressed).\
2384 The registered hotkeys will be updated everytime this function is called.\
2385 @param <KeyEvent - event>\
2386]]\
2387function MKeyHandler:handleKey( event )\
2388 local keyCode = event.keyCode\
2389 if event.sub == \"DOWN\" then\
2390 self.keys[ keyCode ] = event.held\
2391 self:checkHotkeys( keyCode )\
2392 else\
2393 self.keys[ keyCode ] = nil\
2394 self:checkHotkeys()\
2395 end\
2396end\
2397\
2398--[[\
2399 @instance\
2400 @desc Returns true if a key is pressed (regardless of held state) and false otherwise\
2401 @param <number - keyCode>\
2402 @return <boolean - isPressed>\
2403]]\
2404function MKeyHandler:isPressed( keyCode )\
2405 return self.keys[ keyCode ] ~= nil\
2406end\
2407\
2408--[[\
2409 @instance\
2410 @desc Returns true if the key is pressed and held, or false otherwise\
2411 @param <number - keyCode>\
2412 @return <boolean - isHeld>\
2413]]\
2414function MKeyHandler:isHeld( keyCode )\
2415 return self.keys[ keyCode ]\
2416end\
2417\
2418--[[\
2419 @instance\
2420 @desc Breaks 'hotkey' into key names and check their status. The last element of the hotkey must be pressed last (be the active key)\
2421 Hotkey format \"leftCtrl-leftShift-t\" (keyName-keyName-keyName)\
2422 @param <string - hotkey>, [number - key]\
2423 @return <boolean - hotkeyMatch>\
2424]]\
2425function MKeyHandler:matchesHotkey( hotkey, key )\
2426 for segment in hotkey:gmatch \"(%w-)%-\" do\
2427\9\9if self.keys[ keys[ segment ] ] == nil then\
2428\9\9\9return false\
2429 end\
2430\9end\
2431\
2432\9return key == keys[ hotkey:gsub( \".+%-\", \"\" ) ]\
2433end\
2434\
2435--[[\
2436 @instance\
2437 @desc Registers a hotkey by adding it's callback and hotkey string to the handlers 'hotkeys'.\
2438 @param <string - name>, <string - hotkey>, <function - callback>\
2439]]\
2440function MKeyHandler:registerHotkey( name, hotkey, callback )\
2441 if not ( type( name ) == \"string\" and type( hotkey ) == \"string\" and type( callback ) == \"function\" ) then\
2442 return error \"Expected string, string, function\"\
2443 end\
2444\
2445 self.hotkeys[ name ] = { hotkey, callback }\
2446end\
2447\
2448--[[\
2449 @instance\
2450 @desc Iterates through the registered hotkeys and checks for matches using 'matchesHotkey'. If a hotkey matches it's registered callback is invoked\
2451 @param [number - key]\
2452]]\
2453function MKeyHandler:checkHotkeys( key )\
2454 for _, hotkey in pairs( self.hotkeys ) do\
2455 if self:matchesHotkey( hotkey[ 1 ], key ) then\
2456 hotkey[ 2 ]( self, key )\
2457 end\
2458 end\
2459end\
2460",
2461["TML.ti"]="--[[\
2462 @local\
2463 @desc Creates a table of arguments using the classes constructor configuration. This table is then unpacked (and the result returned)\
2464 @param <Class Base - class>, <table - target>\
2465 @return [var - args...]\
2466]]\
2467local function formArguments( class, target )\
2468 local reg = class:getRegistry()\
2469 local constructor, alias, args = reg.constructor, reg.alias, target.arguments\
2470 local returnArguments, trailingTable, dynamics = {}, {}, {}\
2471\
2472 if not constructor then return nil end\
2473 local argumentTypes = constructor.argumentTypes\
2474\
2475 local ordered, set, target = constructor.orderedArguments, {}\
2476 for i = 1, #ordered do\
2477 target = ordered[ i ]\
2478 local argType = argumentTypes[ alias[ target ] or target ]\
2479\
2480 local val = args[ target ]\
2481 if val then\
2482 local escaped, rest = val:match \"^(%%*)%$(.*)$\"\
2483 if not escaped or #escaped % 2 ~= 0 then\
2484 returnArguments[ i ] = XMLParser.convertArgType( val, argType )\
2485 else\
2486 returnArguments[ i ] = argType == \"string\" and \"\" or ( argType == \"number\" and 1 or ( argType == \"boolean\" ) ) or error \"invalid argument type\"\
2487 dynamics[ target ] = DynamicEqParser( rest )\
2488 end\
2489 end\
2490\
2491 set[ ordered[ i ] ] = true\
2492 end\
2493\
2494 for argName, argValue in pairs( args ) do\
2495 if not set[ argName ] then\
2496 trailingTable[ argName ] = XMLParser.convertArgType( argValue, argumentTypes[ alias[ argName ] or argName ] )\
2497 end\
2498 end\
2499\
2500 if next( trailingTable ) then\
2501 returnArguments[ #ordered + 1 ] = trailingTable\
2502 end\
2503\
2504 return class( unpack( returnArguments, 1, next(trailingTable) and #ordered + 1 or #ordered ) ), dynamics\
2505end\
2506\
2507--[[\
2508 The TML class \"is\" used to parse an XML tree into Titanium nodes.\
2509]]\
2510\
2511class \"TML\" {\
2512 tree = false;\
2513 parent = false;\
2514}\
2515\
2516--[[\
2517 @constructor\
2518 @desc Constructs the TML instance by storing the parent and tree on 'self' and then parsing the tree.\
2519 @param <Class Instance - parent>, <table - tree>\
2520]]\
2521function TML:__init__( parent, source )\
2522 self.parent = parent\
2523 self.tree = XMLParser( source ).tree\
2524\
2525 self:parseTree()\
2526end\
2527\
2528--[[\
2529 @instance\
2530 @desc Parses 'self.tree' by creating and adding node instances to their parents.\
2531]]\
2532function TML:parseTree()\
2533 local queue = { { self.parent, self.tree } }\
2534\
2535 local i, toSetup, parent, tree = 1, {}\
2536 while i <= #queue do\
2537 parent, tree = queue[ i ][ 1 ], queue[ i ][ 2 ]\
2538\
2539 local target\
2540 for t = 1, #tree do\
2541 target = tree[ t ]\
2542\
2543 if parent:can \"addTMLObject\" then\
2544 local obj, children = parent:addTMLObject( target )\
2545 if obj and children then\
2546 table.insert( queue, { obj, children } )\
2547 end\
2548 else\
2549 local classArg = target.arguments[\"class\"]\
2550 if classArg then target.arguments[\"class\"] = nil end\
2551\
2552 local itemClass = Titanium.getClass( target.type ) or error( \"Failed to spawn XML tree. Failed to find class '\"..target.type..\"'\" )\
2553 if not Titanium.typeOf( itemClass, \"Node\" ) and target.type ~= \"Page\" then --TODO: Remove this page exception when issue #28 is resolved\
2554 error(\"Failed to spawn XML tree. Class '\"..target.type..\"' is not a valid node\")\
2555 end\
2556\
2557 local itemInstance, dynamics = formArguments( itemClass, target )\
2558 if classArg then\
2559 itemInstance.classes = type( itemInstance.classes ) == \"table\" and itemInstance.classes or {}\
2560 for className in classArg:gmatch \"%S+\" do\
2561 itemInstance.classes[ className ] = true\
2562 end\
2563 end\
2564\
2565 if target.children then\
2566 table.insert( queue, { itemInstance, target.children } )\
2567 end\
2568\
2569 toSetup[ #toSetup + 1 ] = { itemInstance, dynamics }\
2570 if parent:can \"addNode\" then\
2571 parent:addNode( itemInstance )\
2572 else\
2573 return error(\"Failed to spawn XML tree. \"..tostring( parent )..\" cannot contain nodes.\")\
2574 end\
2575 end\
2576 end\
2577\
2578 i = i + 1\
2579 end\
2580\
2581 for i = 1, #toSetup do\
2582 local instance = toSetup[ i ][ 1 ]\
2583\
2584 for property, config in pairs( toSetup[ i ][ 2 ] ) do\
2585 --TODO: Resolve node queries\
2586\
2587 instance:dynamicallyLinkProperty( property, config:resolveStacks( instance ), config.output )\
2588 end\
2589 end\
2590end\
2591\
2592--[[\
2593 @static\
2594 @desc Reads the data from 'path' and creates a TML instance with the contents as the source (arg #2)\
2595 @param <Class Instance - parent>, <string - path>\
2596 @return <TML Instance - instance>\
2597]]\
2598function TML.static.fromFile( parent, path )\
2599 if not Titanium.isInstance( parent ) then\
2600 return error \"Expected Titanium instance as first argument (parent)\"\
2601 end\
2602\
2603 if not fs.exists( path ) then return error( \"Path \"..tostring( path )..\" cannot be found\" ) end\
2604\
2605 local h = fs.open( path, \"r\" )\
2606 local content = h.readAll()\
2607 h.close()\
2608\
2609 return TML( parent, content )\
2610end\
2611",
2612["MThemeable.ti"]="--[[\
2613 The MThemeable mixin \"facilitates\" the use of themes on objects.\
2614 It allows properties to be registered allowing the object to monitor property changes and apply them correctly.\
2615\
2616 The mixin \"stores\" all properties set directly on the object in `mainValues`. These values are prioritised over values from themes unless the theme rule is designated as 'important'.\
2617\
2618 This mixin \"no\" longer handles property links as this functionality has been replaced by a more robust system 'MPropertyManager'.\
2619]]\
2620\
2621class \"MThemeable\" abstract() {\
2622 isUpdating = false;\
2623 hooked = false;\
2624\
2625 properties = {};\
2626 classes = {};\
2627 applicableRules = {};\
2628\
2629 mainValues = {}; --TODO: Preserve dynamic values, instead of the dynamic value output so that they can be restored fully\
2630 defaultValues = {};\
2631}\
2632\
2633--[[\
2634 @instance\
2635 @desc Registers the properties provided. These properties are monitored for changes.\
2636 @param <string - property>, ...\
2637]]\
2638function MThemeable:register( ... )\
2639 if self.hooked then return error \"Cannot register new properties while hooked. Unhook the theme handler before registering new properties\" end\
2640\
2641 local args = { ... }\
2642 for i = 1, #args do\
2643 self.properties[ args[ i ] ] = true\
2644 end\
2645end\
2646\
2647--[[\
2648 @instance\
2649 @desc Unregisters properties provided\
2650 @param <string - property>, ...\
2651]]\
2652function MThemeable:unregister( ... )\
2653 if self.hooked then return error \"Cannot unregister properties while hooked. Unhook the theme handler before unregistering properties\" end\
2654\
2655 local args = { ... }\
2656 for i = 1, #args do\
2657 self.properties[ args[ i ] ] = nil\
2658 end\
2659end\
2660\
2661--[[\
2662 @instance\
2663 @desc Hooks into the instance by creating watch instructions that inform the mixin \"of\" property changes.\
2664]]\
2665function MThemeable:hook()\
2666 if self.hooked then return error \"Failed to hook theme handler. Already hooked\" end\
2667\
2668 for property in pairs( self.properties ) do\
2669 self:watchProperty( property, function( _, __, value )\
2670 if self.isUpdating then return end\
2671\
2672 self.mainValues[ property ] = value\
2673 return self:fetchPropertyValue( property )\
2674 end, \"THEME_HOOK_\" .. self.__ID )\
2675\
2676 self[ self.__resolved[ property ] and \"mainValues\" or \"defaultValues\" ][ property ] = self[ property ]\
2677 end\
2678\
2679 self.hooked = true\
2680end\
2681\
2682--[[\
2683 @instance\
2684 @desc Removes the watch instructions originating from this mixin (identified by 'THEME_HOOK_<ID>' name)\
2685]]\
2686function MThemeable:unhook()\
2687 if not self.hooked then return error \"Failed to unhook theme handler. Already unhooked\" end\
2688 self:unwatchProperty( \"*\", \"THEME_HOOK_\" .. self.__ID )\
2689\
2690 self.hooked = false\
2691end\
2692\
2693function MThemeable:fetchPropertyValue( property )\
2694 local newValue = self.mainValues[ property ]\
2695 local requireImportant = newValue ~= nil\
2696\
2697 local rules, r, usedRule = self.applicableRules\
2698 for i = 1, #rules do\
2699 r = rules[ i ]\
2700 if r.property == property and ( not requireImportant or r.important ) then\
2701 newValue = r.value\
2702 usedRule = r\
2703\
2704 if r.important then requireImportant = true end\
2705 end\
2706 end\
2707\
2708 return newValue, usedRule\
2709end\
2710\
2711--[[\
2712 @instance\
2713 @desc Fetches the value from the application by checking themes for valid rules. If a theme value is found it is applied directly (this does trigger the setter)\
2714 @param <string - property>\
2715]]\
2716function MThemeable:updateProperty( property )\
2717 if not self.properties[ property ] then\
2718 return error( \"Failed to update property '\"..tostring( property )..\"'. Property not registered\" )\
2719 end\
2720\
2721 --TODO: Look into removing old dynamic values when the theme rule is no longer used. Manual dynamicValues need to be distinguished from those created automatically. Ugh.\
2722 local new, rule = self:fetchPropertyValue( property )\
2723 self.isUpdating = true\
2724 if new then\
2725 if rule and rule.isDynamic then\
2726 if self.binds[ property ] then self:unlinkProperties( self, property ) end\
2727\
2728 self:dynamicallyLinkProperty( property, new:resolveStacks( self ), new.output )\
2729 else\
2730 self[ property ] = new\
2731 end\
2732 elseif self[ property ] ~= self.mainValues[ property ] then --TODO: Check if this elseif is needed, or if simply else will suffice\
2733 --TODO: Investigate the use of this statement to ensure 'false' main values are not being overriden by the default values\
2734 self[ property ] = self.mainValues[ property ] or self.defaultValues[ property ]\
2735 end\
2736\
2737 self.isUpdating = false\
2738end\
2739\
2740function MThemeable:queueUpdate()\
2741 self.needsRuleUpdate = true\
2742end\
2743\
2744--[[\
2745 @instance\
2746 @desc Updates each registered property\
2747]]\
2748function MThemeable:updateProperties()\
2749 if self.needsRuleUpdate and self.application then\
2750 self.needsRuleUpdate = false\
2751 self.application:cacheApplicableRulesForType( self.__type )\
2752 end\
2753\
2754 for property in pairs( self.properties ) do self:updateProperty( property ) end\
2755end\
2756\
2757--[[\
2758 @instance\
2759 @desc Adds class 'class' and updated TML properties\
2760 @param <string - class>\
2761]]\
2762function MThemeable:addClass( class )\
2763 self.classes[ class ] = true\
2764 self:queueUpdate()\
2765 self:updateProperties()\
2766end\
2767\
2768--[[\
2769 @instance\
2770 @desc Removes class 'class' and updated TML properties\
2771 @param <string - class>\
2772]]\
2773function MThemeable:removeClass( class )\
2774 self.classes[ class ] = nil\
2775 self:queueUpdate()\
2776 self:updateProperties()\
2777end\
2778\
2779--[[\
2780 @instance\
2781 @desc Shortcut method to set class \"if\" 'has' is truthy or remove it otherwise (updates properties too)\
2782 @param <string - class>, [var - has]\
2783]]\
2784function MThemeable:setClass( class, has )\
2785 self.classes[ class ] = has and true or nil\
2786 self:queueUpdate()\
2787 self:updateProperties()\
2788end\
2789\
2790--[[\
2791 @instance\
2792 @desc Returns true if:\
2793 - Param passed is a table and all values inside the table are set as classes on this object\
2794 - Param is string and this object has that class\
2795 @param <string|table - class>\
2796 @return <boolean - has>\
2797]]\
2798function MThemeable:hasClass( t )\
2799 if type( t ) == \"string\" then\
2800 return self.classes[ t ]\
2801 elseif type( t ) == \"table\" then\
2802 for i = 1, #t do\
2803 if not self.classes[ t[ i ] ] then\
2804 return false\
2805 end\
2806 end\
2807\
2808 return true\
2809 else\
2810 return error(\"Invalid target '\"..tostring( t )..\"' for class check\")\
2811 end\
2812end\
2813\
2814function MThemeable:onThemeUpdate()\
2815 self:updateProperties()\
2816end\
2817",
2818["RadioButton.ti"]="class \"RadioButton\" extends \"Checkbox\" {\
2819 static = {\
2820 groups = {}\
2821 };\
2822\
2823 group = false;\
2824}\
2825\
2826function RadioButton:__init__( ... )\
2827 self:super( ... )\
2828\
2829 if self.toggled then\
2830 RadioButton.deselectInGroup( self.group, self )\
2831 end\
2832end\
2833\
2834function RadioButton:select( ... )\
2835 RadioButton.deselectInGroup( self.group )\
2836\
2837 self.toggled = true\
2838 self:executeCallbacks \"select\"\
2839end\
2840\
2841function RadioButton:onMouseUp( event, handled, within )\
2842 if not handled and within and self.active then\
2843 self:select( event, handled, within )\
2844\
2845 event.handled = true\
2846 end\
2847\
2848 self.active = false\
2849end\
2850\
2851function RadioButton:onLabelClicked( label, event, handled, within )\
2852 self:select( event, handled, within, label )\
2853 event.handled = true\
2854end\
2855\
2856function RadioButton:setGroup( group )\
2857 if self.group then\
2858 RadioButton.removeFromGroup( self, self.group )\
2859 end\
2860 self.group = group\
2861\
2862 RadioButton.addToGroup( self, group )\
2863end\
2864\
2865function RadioButton.static.addToGroup( node, group )\
2866 local g = RadioButton.groups[ group ]\
2867 if type( g ) == \"table\" then\
2868 RadioButton.removeFromGroup( node, group )\
2869\
2870 table.insert( g, node )\
2871 else\
2872 RadioButton.groups[ group ] = { node }\
2873 end\
2874end\
2875\
2876function RadioButton.static.removeFromGroup( node, group )\
2877 local index = RadioButton.isInGroup( node, group )\
2878 if index then\
2879 table.remove( RadioButton.groups[ group ], index )\
2880\
2881 if #RadioButton.groups[ group ] == 0 then\
2882 RadioButton.groups[ group ] = nil\
2883 end\
2884 end\
2885end\
2886\
2887function RadioButton.static.isInGroup( node, group )\
2888 local g = RadioButton.groups[ group ]\
2889 for i = 1, #g do\
2890 if g[ i ] == node then return i end\
2891 end\
2892\
2893 return false\
2894end\
2895\
2896function RadioButton.static.deselectInGroup( group, target )\
2897 local g = RadioButton.groups[ group ]\
2898\
2899 for i = 1, #g do if ( not target or ( target and g[ i ] ~= target ) ) then g[ i ].toggled = false end end\
2900end\
2901\
2902function RadioButton.static.getValue( group )\
2903 local g = RadioButton.groups[ group ]\
2904 if g then\
2905 local radio\
2906 for i = 1, #g do\
2907 radio = g[ i ]\
2908 if radio.toggled then return radio.value end\
2909 end\
2910 end\
2911end\
2912\
2913configureConstructor({\
2914 orderedArguments = { \"X\", \"Y\", \"group\" },\
2915 requiredArguments = { \"group\" },\
2916 argumentTypes = { group = \"string\" },\
2917 useProxy = { \"group\" }\
2918}, true, true )\
2919",
2920["DynamicEqLexer.ti"]="class \"DynamicEqLexer\" extends \"Lexer\"\
2921\
2922function DynamicEqLexer:lexNumber()\
2923 local stream = self:trimStream()\
2924 local exp, following = stream:match \"^%d*%.?%d+(e)([-+]?%d*)\"\
2925\
2926 if exp and exp ~= \"\" then\
2927 if following and following ~= \"\" then\
2928 self:pushToken { type = \"NUMBER\", value = self:consumePattern \"^%d*%.?%d+e[-+]?%d*\" }\
2929 return true\
2930 else self:throw \"Invalid number. Expected digit after 'e'\" end\
2931 elseif stream:find \"^%d*%.?%d+\" then\
2932 self:pushToken { type = \"NUMBER\", value = self:consumePattern \"^%d*%.?%d+\" }\
2933 return true\
2934 end\
2935end\
2936\
2937function DynamicEqLexer:tokenize()\
2938 local stream = self:trimStream()\
2939 local first = stream:sub( 1, 1 )\
2940\
2941 if stream:find \"^%b{}\" then\
2942 self:pushToken { type = \"QUERY\", value = self:consumePattern \"^%b{}\" }\
2943 elseif not self:lexNumber() then\
2944 if first == \"'\" or first == '\"' then\
2945 self:pushToken { type = \"STRING\", value = self:consumeString( first ), surroundedBy = first }\
2946 elseif stream:find \"^and\" then\
2947 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^and\", binary = true }\
2948 elseif stream:find \"^or\" then\
2949 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^or\", binary = true }\
2950 elseif stream:find \"^not\" then\
2951 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^not\", unary = true }\
2952 elseif stream:find \"^[#]\" then\
2953 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^[#]\", unary = true }\
2954 elseif stream:find \"^[/%*%%]\" then\
2955 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^[/%*%%]\", binary = true }\
2956 elseif stream:find \"^%.%.\" then\
2957 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^%.%.\", binary = true }\
2958 elseif stream:find \"^%=%=\" then\
2959 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^%=%=\", binary = true }\
2960 elseif stream:find \"^[%+%-]\" then\
2961 self:pushToken { type = \"OPERATOR\", value = self:consumePattern \"^[%+%-]\", ambiguos = true }\
2962 elseif stream:find \"^[%(%)]\" then\
2963 self:pushToken { type = \"PAREN\", value = self:consumePattern \"^[%(%)]\" }\
2964 elseif stream:find \"^%.\" then\
2965 self:pushToken { type = \"DOT\", value = self:consumePattern \"^%.\" }\
2966 elseif stream:find \"^%w+\" then\
2967 self:pushToken { type = \"NAME\", value = self:consumePattern \"^%w+\" }\
2968 else\
2969 self:throw(\"Unexpected block '\".. ( stream:match( \"%S+\" ) or \"\" ) ..\"'\")\
2970 end\
2971 end\
2972end\
2973",
2974["XMLParser.ti"]="--[[\
2975 The XMLParser class \"is\" used to handle the lexing and parsing of XMLParser source into a parse tree.\
2976]]\
2977\
2978class \"XMLParser\" extends \"Parser\" {\
2979 tokens = false;\
2980 tree = false;\
2981}\
2982\
2983--[[\
2984 @constructor\
2985 @desc Creates a 'Lexer' instance with the source and stores the tokens provided. Invokes 'parse' once lexical analysis complete.\
2986]]\
2987function XMLParser:__init__( source )\
2988 local lex = XMLLexer( source )\
2989 self:super( lex.tokens )\
2990end\
2991\
2992--[[\
2993 @instance\
2994 @desc Iterates through every token and constructs a tree of XML layers\
2995]]\
2996function XMLParser:parse()\
2997 local stack, top, token = {{}}, false, self:stepForward()\
2998 local isTagOpen, settingAttribute\
2999\
3000 while token do\
3001 if settingAttribute then\
3002 if token.type == \"XML_ATTRIBUTE_VALUE\" or token.type == \"XML_STRING_ATTRIBUTE_VALUE\" then\
3003 top.arguments[ settingAttribute ] = token.value\
3004 settingAttribute = false\
3005 else\
3006 self:throw( \"Unexpected \"..token.type..\". Expected attribute value following XML_ASSIGNMENT token.\" )\
3007 end\
3008 else\
3009 if token.type == \"XML_OPEN\" then\
3010 if isTagOpen then\
3011 self:throw \"Unexpected XML_OPEN token. Expected XML attributes or end of tag.\"\
3012 end\
3013 isTagOpen = true\
3014\
3015 top = { type = token.value, arguments = {} }\
3016 table.insert( stack, top )\
3017 elseif token.type == \"XML_END\" then\
3018 local toClose = table.remove( stack )\
3019 top = stack[ #stack ]\
3020\
3021 if not top then\
3022 self:throw(\"Nothing to close with XML_END of type '\"..token.value..\"'\")\
3023 elseif toClose.type ~= token.value then\
3024 self:throw(\"Tried to close \"..toClose.type..\" with XML_END of type '\"..token.value..\"'\")\
3025 end\
3026\
3027 if not top.children then top.children = {} end\
3028 table.insert( top.children, toClose )\
3029 elseif token.type == \"XML_END_CLOSE\" then\
3030 top = stack[ #stack - 1 ]\
3031\
3032 if not top then\
3033 self:throw(\"Unexpected XML_END_CLOSE tag (/>)\")\
3034 end\
3035\
3036 if not top.children then top.children = {} end\
3037 table.insert( top.children, table.remove( stack ) )\
3038 elseif token.type == \"XML_CLOSE\" then\
3039 isTagOpen = false\
3040 elseif token.type == \"XML_ATTRIBUTE\" then\
3041 local next = self:stepForward()\
3042\
3043 if next.type == \"XML_ASSIGNMENT\" then\
3044 settingAttribute = token.value\
3045 else\
3046 top.arguments[ token.value ] = true\
3047 self.position = self.position - 1\
3048 end\
3049 elseif token.type == \"XML_CONTENT\" then\
3050 if not top.type then\
3051 self:throw(\"Unexpected XML_CONTENT. Invalid content: \"..token.value)\
3052 end\
3053\
3054 top.content = token.value\
3055 else\
3056 self:throw(\"Unexpected \"..token.type)\
3057 end\
3058 end\
3059\
3060 if token.type == \"XML_END\" or token.type == \"XML_END_CLOSE\" then\
3061 isTagOpen = false\
3062 end\
3063\
3064 if top.content and top.children then\
3065 self:throw \"XML layers cannot contain child nodes and XML_CONTENT at the same time\"\
3066 end\
3067\
3068 token = self:stepForward()\
3069 end\
3070 self.tree = stack[ 1 ].children\
3071end\
3072\
3073--[[\
3074 @static\
3075 @desc When lexing the XML arguments they are all stored as strings as a result of the string operations to find tokens.\
3076 This function converts a value to the type given (#2)\
3077 @param <var - argumentValue>, <string - desiredType>\
3078 @return <desiredType* - value>\
3079\
3080 *Note: desiredType is passed as type string, however the return is the value type defined inside the string. eg: desiredType: \"number\" will return a number, not a string.\
3081]]\
3082function XMLParser.static.convertArgType( argumentValue, desiredType )\
3083 local vType = type( argumentValue )\
3084 argumentValue = vType == \"number\" and math.ceil( argumentValue ) or argumentValue\
3085\
3086 if not desiredType or not argumentValue or vType == desiredType then\
3087 return argumentValue\
3088 end\
3089\
3090 if desiredType == \"string\" then\
3091 return tostring( argumentValue )\
3092 elseif desiredType == \"number\" then\
3093 return tonumber( argumentValue ) and math.ceil( tonumber( argumentValue ) ) or error( \"Failed to cast argument to number. Value: \"..tostring( argumentValue )..\" is not a valid number\" )\
3094 elseif desiredType == \"boolean\" then\
3095 if argumentValue == \"true\" then return true\
3096 elseif argumentValue == \"false\" then return false\
3097 else\
3098 return error( \"Failed to cast argument to boolean. Value: \"..tostring( argumentValue )..\" is not a valid boolean (true or false)\" )\
3099 end\
3100 elseif desiredType == \"colour\" or desiredType == \"color\" then\
3101 if argumentValue == \"transparent\" or argumentValue == \"trans\" then\
3102 return 0\
3103 end\
3104 return tonumber( argumentValue ) or colours[ argumentValue ] or colors[ argumentValue ] or error( \"Failed to cast argument to colour (number). Value: \"..tostring( argumentValue )..\" is not a valid colour\" )\
3105 else\
3106 return error( \"Failed to cast argument. Unknown target type '\"..tostring( desiredType )..\"'\" )\
3107 end\
3108end\
3109",
3110["Image.ti"]="local function getFileExtension( path )\
3111 return path:match \".+%.(.-)$\" or \"\"\
3112end\
3113\
3114class \"Image\" extends \"Node\" {\
3115 static = { imageParsers = {} };\
3116 imagePath = false;\
3117}\
3118\
3119function Image:__init__( ... )\
3120 self:super()\
3121 self:resolve( ... )\
3122end\
3123\
3124--[[\
3125 @instance\
3126 @desc Depending on the file extension (self.path), an image parser will be called.\
3127 To add support for more extensions, simply add the function to the classes static ( Image.static.addParser( extension, function ) )\
3128]]\
3129function Image:parseImage()\
3130 local path = self.path\
3131 if type( path ) ~= \"string\" then\
3132 return error(\"Failed to parse image, path '\"..tostring( path )..\"' is invalid\")\
3133 elseif not fs.exists( path ) or fs.isDir( path ) then\
3134 return error(\"Failed to parse image, path '\"..path..\"' is invalid and cannot be opened for parsing\")\
3135 end\
3136\
3137 local ext = getFileExtension( path )\
3138 if not Image.imageParsers[ ext ] then\
3139 return error(\"Failed to parse image, no image parser exists for \" .. ( ext == \"\" and \"'no ext'\" or \"'.\" .. ext .. \"'\" ) .. \" files for '\"..path..\"'\")\
3140 end\
3141\
3142 local f = fs.open( path, \"r\" )\
3143 local stream = f.readAll()\
3144 f.close()\
3145\
3146 local width, height, pixels = Image.imageParsers[ ext ]( stream )\
3147 for y = 1, height do\
3148 local pos = ( y - 1 ) * width\
3149 for x = 1, width do\
3150 local posX = pos + x\
3151 self.canvas.buffer[ posX ] = pixels[ posX ] or { \" \" }\
3152 end\
3153 end\
3154\
3155 self.width, self.height = width, height\
3156 self.changed = true\
3157end\
3158\
3159function Image:setPath( path )\
3160 self.path = path\
3161 self:parseImage()\
3162end\
3163\
3164function Image.static.setImageParser( extension, parserFunction )\
3165 if type( extension ) ~= \"string\" or type( parserFunction ) ~= \"function\" then\
3166 return error \"Failed to set image parser. Invalid arguments, expected string, function\"\
3167 end\
3168\
3169 Image.static.imageParsers[ extension ] = parserFunction\
3170\
3171 return Image\
3172end\
3173\
3174function Image:draw() end\
3175configureConstructor {\
3176 orderedArguments = { \"path\" },\
3177 requiredArguments = { \"path\" },\
3178 useProxy = { \"path\" },\
3179 argumentTypes = {\
3180 path = \"string\"\
3181 }\
3182}\
3183",
3184["Dropdown.ti"]="class \"Dropdown\" extends \"Container\" {\
3185 maxHeight = false;\
3186\
3187 prompt = \"Please select\";\
3188 horizontalAlign = \"left\";\
3189\
3190 openIndicator = \" \\31\";\
3191 closedIndicator = \" \\16\";\
3192\
3193 backgroundColour = colours.lightBlue;\
3194 colour = colours.white;\
3195\
3196 activeBackgroundColour = colours.cyan;\
3197\
3198 selectedColour = colours.white;\
3199 selectedBackgroundColour = colours.grey;\
3200 selectedOption = false;\
3201 options = {};\
3202}\
3203\
3204function Dropdown:__init__( ... )\
3205 self:super( ... )\
3206\
3207 self.optionDisplay = self:addNode( Button \"\":linkProperties( self, \"horizontalAlign\", \"disabledColour\", \"disabledBackgroundColour\", \"activeColour\", \"activeBackgroundColour\" ):on(\"trigger\", function() self:toggleOptionDisplay() end) )\
3208 self.optionContainer = self:addNode( ScrollContainer( 1, 2, self.width ):set{ xScrollAllowed = false } )\
3209\
3210 self:closeOptionDisplay()\
3211\
3212 self.transparent = true\
3213 self.consumeAll = false\
3214end\
3215\
3216function Dropdown:closeOptionDisplay()\
3217 local cont = self.optionContainer\
3218 cont.visible, cont.enabled = false, false\
3219\
3220 self:queueAreaReset()\
3221 self:updateDisplayButton()\
3222end\
3223\
3224function Dropdown:openOptionDisplay()\
3225 local cont = self.optionContainer\
3226 cont.visible, cont.enabled = true, true\
3227\
3228 self:queueAreaReset()\
3229 self:updateDisplayButton()\
3230end\
3231\
3232function Dropdown:toggleOptionDisplay()\
3233 if self.optionContainer.visible then\
3234 self:closeOptionDisplay()\
3235 else\
3236 self:openOptionDisplay()\
3237 end\
3238end\
3239\
3240function Dropdown:setEnabled( enabled )\
3241 self.super:setEnabled( enabled )\
3242 if not enabled then\
3243 self:closeOptionDisplay()\
3244 end\
3245end\
3246\
3247function Dropdown:updateDisplayButton()\
3248 self.optionDisplay.text = ( type( self.selectedOption ) == \"table\" and self.selectedOption[ 1 ] or self.prompt ) .. ( self.optionContainer.visible and self.openIndicator or self.closedIndicator )\
3249 self.optionDisplay.width = #self.optionDisplay.text\
3250\
3251 self.optionDisplay:set {\
3252 colour = self.selectedColour,\
3253 backgroundColour = self.selectedBackgroundColour\
3254 }\
3255end\
3256\
3257function Dropdown:updateOptions()\
3258 local cont = self.optionContainer\
3259 cont:clearNodes()\
3260\
3261 self:updateDisplayButton()\
3262\
3263 local options = self.options\
3264 for i = 1, #options do\
3265 local option = options[ i ][ 1 ]\
3266 if options[ i ] ~= self.selectedOption then\
3267 cont:addNode(Button( option, 1, #cont.nodes + 1, self.width ):on(\"trigger\", function( this )\
3268 self.selectedOption = options[ i ]\
3269 end):linkProperties( self, \"colour\", \"activeColour\", \"disabledColour\", \"backgroundColour\", \"activeBackgroundColour\", \"disabledBackgroundColour\", \"horizontalAlign\" ))\
3270 end\
3271 end\
3272\
3273 local count = #cont.nodes\
3274 if self.maxHeight then\
3275 cont.height, self.height = math.min( count, self.maxHeight - 1 ), math.min( count + 1, self.maxHeight )\
3276 else\
3277 cont.height, self.height = count, count + 1\
3278 end\
3279\
3280 if #options > 0 then cont.yScroll = math.min( cont.yScroll, count ) end\
3281end\
3282\
3283function Dropdown:getSelectedValue()\
3284 if type( self.selectedOption ) ~= \"table\" then return end\
3285\
3286 return self.selectedOption[ 2 ]\
3287end\
3288\
3289function Dropdown:addOption( option, value )\
3290 if type( option ) ~= \"string\" or value == nil then\
3291 return error \"Failed to add option to Dropdown node. Expected two arguments: string, val - where val is not nil\"\
3292 end\
3293\
3294 self:removeOption( option )\
3295 table.insert( self.options, { option, value } )\
3296\
3297 self:updateOptions()\
3298end\
3299\
3300function Dropdown:removeOption( option )\
3301 local options = self.options\
3302 for i = #options, 1, -1 do\
3303 if options[ i ] == option then\
3304 table.remove( options, i )\
3305 end\
3306 end\
3307\
3308 self:updateOptions()\
3309end\
3310\
3311function Dropdown:setPrompt( prompt )\
3312 self.prompt = prompt\
3313 self.optionDisplay.text = prompt\
3314end\
3315\
3316function Dropdown:setSelectedOption( selected )\
3317 self.selectedOption = selected\
3318 self:closeOptionDisplay()\
3319 self:updateOptions()\
3320\
3321 self:executeCallbacks( \"change\", selected )\
3322end\
3323\
3324function Dropdown:handle( eventObj )\
3325 if not self.super:handle( eventObj ) then return end\
3326\
3327 if eventObj:is \"mouse_click\" and not self:isMouseColliding( eventObj ) and self.optionContainer.visible then\
3328 self:closeOptionDisplay()\
3329 eventObj.handled = true\
3330 end\
3331\
3332 return true\
3333end\
3334\
3335function Dropdown:addTMLObject( TMLObj )\
3336 if TMLObj.type == \"Option\" then\
3337 if TMLObj.content and TMLObj.arguments.value then\
3338 self:addOption( TMLObj.content, TMLObj.arguments.value )\
3339 else\
3340 error \"Failed to add TML object to Dropdown object. 'Option' tag must include content (not children) and a 'value' argument\"\
3341 end\
3342 else\
3343 error( \"Failed to add TML object to Dropdown object. Only 'Option' tags are accepted, '\" .. tostring( TMLObj.type ) .. \"' is invalid\" )\
3344 end\
3345end\
3346\
3347configureConstructor({\
3348 orderedArguments = { \"X\", \"Y\", \"width\", \"maxHeight\", \"prompt\" },\
3349 argumentTypes = {\
3350 maxHeight = \"number\",\
3351 prompt = \"string\"\
3352 }\
3353}, true)\
3354",
3355["Terminal.ti"]="local function isThreadRunning( obj )\
3356 if not obj.thread then return false end\
3357\
3358 return obj.thread.running\
3359end\
3360\
3361class \"Terminal\" extends \"Node\" mixin \"MFocusable\" {\
3362 static = {\
3363 focusedEvents = {\
3364 MOUSE = true,\
3365 KEY = true,\
3366 CHAR = true\
3367 }\
3368 };\
3369\
3370 canvas = true;\
3371 displayThreadStatus = true;\
3372}\
3373\
3374function Terminal:__init__( ... )\
3375 self:resolve( ... )\
3376 self:super()\
3377\
3378 self.canvas = RedirectCanvas( self )\
3379 self.redirect = self.canvas:getTerminalRedirect()\
3380end\
3381\
3382function Terminal:wrapChunk()\
3383 if type( self.chunk ) ~= \"function\" then\
3384 return error \"Cannot wrap chunk. No chunk function set.\"\
3385 end\
3386\
3387 self.canvas:resetTerm()\
3388\
3389 self.thread = Thread( self.chunk )\
3390 self:resume( GenericEvent \"titanium_terminal_start\" )\
3391end\
3392\
3393function Terminal:resume( event )\
3394 if not isThreadRunning( self ) then return end\
3395\
3396 if not Titanium.typeOf( event, \"Event\", true ) then\
3397 return error \"Invalid event object passed to resume terminal thread\"\
3398 end\
3399\
3400 local thread, old = self.thread, term.redirect( self.redirect )\
3401 thread:filterHandle( event )\
3402 term.redirect( old )\
3403\
3404 if not thread.running then\
3405 if type( thread.exception ) == \"string\" then\
3406 if self.displayThreadStatus then\
3407 self:emulate(function() printError( \"Thread Crashed: \" .. tostring( thread.exception ) ) end)\
3408 end\
3409\
3410 self:executeCallbacks(\"exception\", thread)\
3411 else\
3412 if self.displayThreadStatus then\
3413 self:emulate(function() print \"Finished\" end)\
3414 end\
3415\
3416 self:executeCallbacks(\"graceful_finish\", thread)\
3417 end\
3418\
3419 self:executeCallbacks(\"finish\", thread)\
3420 end\
3421\
3422 self.changed = true\
3423end\
3424\
3425function Terminal:emulate( fn )\
3426 if type( fn ) ~= \"function\" then\
3427 return error(\"Failed to emulate function. '\"..tostring( fn )..\" is not valid'\")\
3428 end\
3429\
3430 local old = term.redirect( self.redirect )\
3431 local ok, err = pcall( fn )\
3432 term.redirect( old )\
3433\
3434 if not ok then\
3435 return error(\"Failed to emulate function. Error: \"..tostring( err ), 3)\
3436 end\
3437end\
3438\
3439function Terminal:setChunk( chunk )\
3440 self.chunk = chunk\
3441 self:wrapChunk()\
3442end\
3443\
3444function Terminal:getCaretInfo()\
3445 local c = self.canvas\
3446 return isThreadRunning( self ) and c.tCursor, c.tX + self.X - 1, c.tY + self.Y - 1, c.tColour\
3447end\
3448\
3449function Terminal:handle( eventObj )\
3450 if eventObj.handled or not isThreadRunning( self ) then return end\
3451\
3452 if eventObj.main == \"MOUSE\" then\
3453 if eventObj:withinParent( self ) then self:focus() else self:unfocus() end\
3454 eventObj = eventObj:clone( self )\
3455 end\
3456\
3457 if Terminal.focusedEvents[ eventObj.main ] and not self.focused then return end\
3458 self:resume( eventObj )\
3459end\
3460\
3461function Terminal:draw( force ) end\
3462\
3463configureConstructor({\
3464 orderedArguments = { \"X\", \"Y\", \"width\", \"height\", \"chunk\" },\
3465 argumentTypes = { chunk = \"function\" },\
3466 useProxy = { \"chunk\" }\
3467}, true)\
3468",
3469["Thread.ti"]="class \"Thread\" {\
3470 running = false;\
3471\
3472 func = false;\
3473 co = false;\
3474\
3475 filter = false;\
3476 exception = false;\
3477\
3478 titaniumEvents = false;\
3479}\
3480\
3481function Thread:__init__( ... )\
3482 self:resolve( ... )\
3483 self:start()\
3484end\
3485\
3486function Thread:start()\
3487 self.co = coroutine.create( self.func )\
3488 self.running = true\
3489 self.filter = false\
3490end\
3491\
3492function Thread:stop()\
3493 self.running = false\
3494end\
3495\
3496function Thread:filterHandle( eventObj )\
3497 if self.titaniumEvents then\
3498 self:handle( eventObj )\
3499 else\
3500 self:handle( unpack( eventObj.data ) )\
3501 end\
3502end\
3503\
3504function Thread:handle( ... )\
3505 if not self.running then return false end\
3506\
3507 local tEvents, cFilter, eMain, co, ok, filter = self.titaniumEvents, self.filter, select( 1, ... ), self.co\
3508 if tEvents then\
3509 if not cFilter or ( eMain:is( cFilter ) or eMain:is( \"terminate\" ) ) then\
3510 ok, filter = coroutine.resume( co, eMain )\
3511 else return end\
3512 else\
3513 if not cFilter or ( eMain == cFilter or eMain == \"terminate\" ) then\
3514 ok, filter = coroutine.resume( co, ... )\
3515 else return end\
3516 end\
3517\
3518 if ok then\
3519 if coroutine.status( co ) == \"dead\" then\
3520 self.running = false\
3521 end\
3522\
3523 self.filter = filter\
3524 else\
3525 self.exception = filter\
3526 self.running = false\
3527 end\
3528end\
3529\
3530configureConstructor {\
3531 orderedArguments = { \"func\", \"titaniumEvents\", \"id\" },\
3532 requiredArguments = { \"func\" }\
3533}\
3534",
3535["NodeQuery.ti"]="local function format( original, symbol, final )\
3536 local wrapper = type( original ) == \"string\" and '\"' or \"\"\
3537 local finalWrapper = type( final ) == \"string\" and '\"' or \"\"\
3538\
3539 return (\"return %s%s%s %s %s%s%s\"):format( wrapper, tostring( original ), wrapper, symbol, finalWrapper, tostring( final ), finalWrapper )\
3540end\
3541\
3542local function testCondition( node, condition )\
3543 local fn, err = loadstring( format( node[ condition.property ], condition.symbol, condition.value ) )\
3544 if fn then return fn() end\
3545\
3546 return fn()\
3547end\
3548\
3549local function queryScope( scope, section, results )\
3550 local last = {}\
3551\
3552 local node\
3553 for i = 1, #scope do\
3554 node = scope[ i ]\
3555\
3556 if ( not section.id or node.id == section.id ) and\
3557 ( not section.type or section.type == \"*\" or node.__type == section.type ) and\
3558 ( not section.classes or node:hasClass( section.classes ) ) then\
3559 local condition, failed = section.condition\
3560 if condition then\
3561 local conditionPart\
3562 for c = 1, #condition do\
3563 if not testCondition( node, condition[ c ] ) then\
3564 failed = true\
3565 break\
3566 end\
3567 end\
3568 end\
3569\
3570 if not failed then\
3571 last[ #last + 1 ] = node\
3572 end\
3573 end\
3574 end\
3575\
3576 return last\
3577end\
3578\
3579local function createScope( results, direct )\
3580 local scope = {}\
3581 for i = 1, #results do\
3582 local innerScope = direct and results[ i ].nodes or results[ i ].collatedNodes\
3583\
3584 for r = 1, #innerScope do\
3585 scope[ #scope + 1 ] = innerScope[ r ]\
3586 end\
3587 end\
3588\
3589 return scope\
3590end\
3591\
3592local function performQuery( query, base )\
3593 local lastResults, section = base\
3594\
3595 for i = 1, #query do\
3596 section = query[ i ]\
3597 lastResults = queryScope( createScope( lastResults, section.direct ), section )\
3598 end\
3599\
3600 return lastResults\
3601end\
3602\
3603class \"NodeQuery\" {\
3604 static = { supportedMethods = { \"addClass\", \"removeClass\", \"setClass\", \"set\", \"animate\", \"on\", \"off\" } };\
3605 result = false;\
3606\
3607 parent = false;\
3608}\
3609\
3610function NodeQuery:__init__( parent, queryString )\
3611 if not ( Titanium.isInstance( parent ) and type( queryString ) == \"string\" ) then\
3612 return error \"Node query requires Titanium instance and string query\"\
3613 end\
3614 self.parent = parent\
3615\
3616 self.parsedQuery = QueryParser( queryString ).query\
3617 self.result = self:query()\
3618\
3619 local sup = NodeQuery.supportedMethods\
3620 for i = 1, #sup do\
3621 self[ sup[ i ] ] = function( self, ... ) self:executeOnNodes( sup[ i ], ... ) end\
3622 end\
3623end\
3624\
3625--[[\
3626 @static\
3627 @desc Returns a table containing the nodes matching the conditions set in 'query'\
3628 @return <table - results>\
3629]]\
3630function NodeQuery:query()\
3631 local query, results = self.parsedQuery, {}\
3632 if type( query ) ~= \"table\" then return error( \"Cannot perform query. Invalid query object passed\" ) end\
3633\
3634 local parent = { self.parent }\
3635 for i = 1, #query do\
3636 local res = performQuery( query[ i ], parent )\
3637\
3638 for r = 1, #res do\
3639 results[ #results + 1 ] = res[ r ]\
3640 end\
3641 end\
3642\
3643 return results\
3644end\
3645\
3646--[[\
3647 @instance\
3648 @desc Returns true if the class 'class' exists on all nodes in the result set, false otherwise\
3649 @param <table|string - class>\
3650 @return <boolean - hasClass>\
3651]]\
3652function NodeQuery:hasClass( class )\
3653 local nodes = self.result\
3654 for i = 1, #nodes do\
3655 if not nodes[ i ]:hasClass( class ) then\
3656 return false\
3657 end\
3658 end\
3659\
3660 return true\
3661end\
3662\
3663function NodeQuery:each( fn )\
3664 local nodes = self.result\
3665 for i = 1, #nodes do\
3666 fn( nodes[ i ] )\
3667 end\
3668end\
3669\
3670--[[\
3671 @instance\
3672 @desc Iterates over each node in the result set, calling 'fnName' with arguments '...' on each\
3673 @param <string - fnName>, [vararg - ...]\
3674]]\
3675function NodeQuery:executeOnNodes( fnName, ... )\
3676 local nodes, node = self.result\
3677 for i = 1, #nodes do\
3678 node = nodes[ i ]\
3679\
3680 if node:can( fnName ) then\
3681 node[ fnName ]( node, ... )\
3682 end\
3683 end\
3684end\
3685",
3686["Page.ti"]="class \"Page\" extends \"ScrollContainer\"\
3687\
3688function Page:setParent( parent )\
3689 self.super:setParent( parent )\
3690\
3691 self.width = parent.width\
3692 self.height = parent.height\
3693end\
3694\
3695configureConstructor {\
3696 orderedArguments = { \"id\" },\
3697 requiredArguments = { \"id\" }\
3698}\
3699",
3700["Input.ti"]="--[[\
3701 The Input class \"provides\" the user with the ability to insert a single line of text.\
3702]]\
3703\
3704local stringRep, stringSub = string.rep, string.sub\
3705class \"Input\" extends \"Node\" mixin \"MActivatable\" mixin \"MFocusable\" {\
3706 position = 0;\
3707 scroll = 0;\
3708 value = \"\";\
3709\
3710 selection = false;\
3711 selectedColour = false;\
3712 selectedBackgroundColour = colours.lightBlue;\
3713\
3714 placeholder = false;\
3715 placeholderColour = 256;\
3716\
3717 allowMouse = true;\
3718 allowKey = true;\
3719 allowChar = true;\
3720\
3721 limit = 0;\
3722 mask = \"\";\
3723}\
3724\
3725--[[\
3726 @constructor\
3727 @desc Constructs the instance by resolving arguments and registering used properties\
3728]]\
3729function Input:__init__( ... )\
3730 self:resolve( ... )\
3731 self:register( \"width\", \"selectedColour\", \"selectedBackgroundColour\", \"limit\" )\
3732\
3733 self:super()\
3734end\
3735\
3736--[[\
3737 @instance\
3738 @desc Sets the input to active if clicked on, sets active and focused to false if the mouse click was not on the input.\
3739 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
3740]]\
3741function Input:onMouseClick( event, handled, within )\
3742 if within and not handled then\
3743 if self.focused then\
3744 local application, pos, width, scroll = self.application, self.position, self.width, self.scroll\
3745 local clickedPos = math.min( #self.value, event.X - self.X + self.scroll )\
3746\
3747 if application:isPressed( keys.leftShift ) or application:isPressed( keys.rightShift ) then\
3748 if clickedPos ~= pos then\
3749 self.selection = clickedPos\
3750 else self.selection = false end\
3751 else self.position, self.selection = clickedPos, false end\
3752 end\
3753\
3754 self.active, event.handled = true, true\
3755 else\
3756 self.active = false\
3757 self:unfocus()\
3758 end\
3759end\
3760\
3761--[[\
3762 @instance\
3763 @desc If a mouse drag occurs while the input is focused, the selection will be moved to the mouse drag location, creating a selection between the cursor position and the drag position\
3764 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
3765]]\
3766function Input:onMouseDrag( event, handled, within )\
3767 if not self.focused or handled then return end\
3768 self.selection = math.min( #self.value, event.X - self.X + self.scroll )\
3769 event.handled = true\
3770end\
3771\
3772--[[\
3773 @instance\
3774 @desc If the mouse up missed the input or the event was already handled, active and false are set to false.\
3775 If within and not handled and input is active focused is set to true. Active is set to false on all conditions.\
3776 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
3777]]\
3778function Input:onMouseUp( event, handled, within )\
3779 if ( not within or handled ) and self.focused then\
3780 self:unfocus()\
3781 elseif within and not handled and self.active and not self.focused then\
3782 self:focus()\
3783 end\
3784\
3785 self.active = false\
3786end\
3787\
3788--[[\
3789 @instance\
3790 @desc Catches char events and inserts the character pressed into the input's value.\
3791 @param <CharEvent - event>, <boolean - handled>\
3792]]\
3793function Input:onChar( event, handled )\
3794 if not self.focused or handled then return end\
3795\
3796 local value, position, selection = self.value, self.position, self.selection\
3797 if selection then\
3798 local start, stop = math.min( selection, position ), math.max( selection, position )\
3799 start = start > stop and start - 1 or start\
3800\
3801 self.value, self.selection = stringSub( value, 1, start ) .. event.char .. stringSub( value, stop + ( start < stop and 1 or 2 ) ), false\
3802 self.position = start + 1\
3803 self.changed = true\
3804 else\
3805 if self.limit > 0 and #value >= self.limit then return end\
3806\
3807 self.value = stringSub( value, 1, position ) .. event.char .. stringSub( value, position + 1 )\
3808 self.position = self.position + 1\
3809 end\
3810\
3811 self:executeCallbacks \"change\"\
3812\
3813 event.handled = true\
3814end\
3815\
3816--[[\
3817 @instance\
3818 @desc Catches key down events and performs an action depending on the key pressed\
3819 @param <KeyEvent - event>, <boolean - handled>\
3820]]\
3821function Input:onKeyDown( event, handled )\
3822 if not self.focused or handled then return end\
3823\
3824 local value, position = self.value, self.position\
3825 local valueLen = #value\
3826 if event.sub == \"DOWN\" then\
3827 local key, selection, position, application = event.keyName, self.selection, self.position, self.application\
3828 local isPressed, start, stop = application:isPressed( keys.leftShift ) or application:isPressed( keys.rightShift )\
3829\
3830 if selection then\
3831 start, stop = selection < position and selection or position, selection > position and selection + 1 or position + 1\
3832 else start, stop = position - 1, position end\
3833\
3834 if key == \"enter\" then\
3835 self:executeCallbacks( \"trigger\", self.value, self.selection and self:getSelectedValue() )\
3836 elseif selection then\
3837 if key == \"delete\" or key == \"backspace\" then\
3838 self.value = stringSub( value, 1, start ) .. stringSub( value, stop )\
3839 self.position = start\
3840 self.selection = false\
3841 elseif not isPressed and ( key == \"left\" or key == \"right\" ) then\
3842 self.position = key == \"left\" and start + 1 or key == \"right\" and stop - 2\
3843 self.selection = false\
3844 end\
3845 end\
3846\
3847 local cSelection = self.selection or self.position\
3848 local function set( offset )\
3849 if isPressed then self.selection = cSelection + offset\
3850 else self.position = self.position + offset; self.selection = false end\
3851 end\
3852\
3853 if key == \"left\" then set( -1 )\
3854 elseif key == \"right\" then set( 1 ) else\
3855 if key == \"home\" then\
3856 set( isPressed and -cSelection or -position )\
3857 elseif key == \"end\" then\
3858 set( isPressed and valueLen - cSelection or valueLen - position )\
3859 elseif key == \"backspace\" and isPressed then\
3860 self.value, self.position = stringSub( self.value, stop + 1 ), 0\
3861 end\
3862 end\
3863\
3864 if not isPressed then\
3865 if key == \"backspace\" and start >= 0 and not selection then\
3866 self.value = stringSub( value, 1, start ) .. stringSub( value, stop + 1 )\
3867 self.position = start\
3868 elseif key == \"delete\" and not selection then\
3869 self.value, self.changed = stringSub( value, 1, stop ) .. stringSub( value, stop + 2 ), true\
3870 end\
3871 end\
3872 end\
3873end\
3874\
3875function Input:onLabelClicked( label, event, handled, within )\
3876 self:focus()\
3877 event.handled = true\
3878end\
3879\
3880--[[\
3881 @instance\
3882 @desc Draws the inputs background and text to the parent canvas\
3883 @param [boolean - force]\
3884]]\
3885function Input:draw( force )\
3886 local raw = self.raw\
3887 if raw.changed or force then\
3888 local canvas, tc, bg = raw.canvas, raw.colour, raw.backgroundColour\
3889 if raw.focused then tc, bg = raw.focusedColour, raw.focusedBackgroundColour\
3890 elseif raw.active then tc, bg = raw.activeColour, raw.activeBackgroundColour end\
3891\
3892 canvas:clear( bg )\
3893\
3894 local position, width, value, selection, placeholder = self.position, self.width, self.mask ~= \"\" and stringRep( self.mask, #self.value ) or self.value, self.selection, self.placeholder\
3895 if self.focused or not placeholder or #value > 0 then\
3896 if self.selection then\
3897 local start, stop = selection < position and selection or position, selection > position and selection + 1 or position + 1\
3898 if start < stop then stop = stop - 1 end\
3899\
3900 local startPos = -self.scroll + 1\
3901\
3902 canvas:drawTextLine( startPos, 1, stringSub( value, 1, start + 1 ), tc, bg )\
3903 canvas:drawTextLine( startPos + start, 1, stringSub( value, start + 1, stop ), self.focused and self.selectedColour or tc, self.focused and self.selectedBackgroundColour or bg )\
3904 canvas:drawTextLine( startPos + stop, 1, stringSub( value, stop + 1 ), tc, bg )\
3905 else\
3906 canvas:drawTextLine( -self.scroll + 1, 1, value, tc, bg )\
3907 end\
3908 else canvas:drawTextLine( 1, 1, stringSub( placeholder, 1, self.width ), self.placeholderColour, bg ) end\
3909\
3910 raw.changed = false\
3911 end\
3912end\
3913\
3914--[[\
3915 @instance\
3916 @desc Attempts to reposition the scroll of the input box depending on the position indicator\
3917 @param <number - indicator>\
3918]]\
3919function Input:repositionScroll( indicator )\
3920 local limit = self.limit\
3921 local isLimit = limit > 0\
3922\
3923 if indicator >= self.width and indicator > ( self.scroll + self.width - 1 ) then\
3924 self.scroll = math.min( indicator - self.width + 1, #self.value - self.width + 1 ) - ( isLimit and indicator >= limit and 1 or 0 )\
3925 elseif indicator <= self.scroll then\
3926 self.scroll = math.max( self.scroll - ( self.scroll - indicator ), 0 )\
3927 else self.scroll = math.max( math.min( self.scroll, #self.value - self.width + 1 ), 0 ) end\
3928end\
3929\
3930--[[\
3931 @instance\
3932 @desc If the given selection is a number, it will be adjusted to fit within the bounds of the input and set. If not, the value will be raw set.\
3933 @param <number|boolean - selection>\
3934]]\
3935function Input:setSelection( selection )\
3936 if type( selection ) == \"number\" then\
3937 local newSelection = math.max( math.min( selection, #self.value ), 0 )\
3938 self.selection = newSelection ~= self.position and newSelection or false\
3939 else self.selection = selection end\
3940\
3941 self:repositionScroll( self.selection or self.position )\
3942 self.changed = true\
3943end\
3944\
3945--[[\
3946 @instance\
3947 @desc Returns the value of the input that is selected\
3948 @return <string - selectedValue>\
3949]]\
3950function Input:getSelectedValue()\
3951 local selection, position = self.selection, self.position\
3952 return stringSub( self.value, ( selection < position and selection or position ) + 1, ( selection > position and selection or position ) )\
3953end\
3954\
3955--[[\
3956 @instance\
3957 @desc If the given position is equal to the (inputs) selection, the selection will be reset.\
3958 If not equal, the value will be adjusted to fit inside the bounds of the input and then set.\
3959 @param <number - pos>\
3960]]\
3961function Input:setPosition( pos )\
3962 if self.selection == pos then self.selection = false end\
3963 self.position, self.changed = math.max( math.min( pos, #self.value ), 0 ), true\
3964\
3965 self:repositionScroll( self.position )\
3966end\
3967\
3968--[[\
3969 @instance\
3970 @desc When called, returns the state of the caret, its position (absolute) and colour.\
3971 @return <boolean - caretEnabled>, <number - caretX>, <number - caretY>, <colour - caretColour>\
3972]]\
3973function Input:getCaretInfo()\
3974 local sX, sY = self:getAbsolutePosition()\
3975 local limit = self.limit\
3976\
3977 return not self.selection and ( limit <= 0 or self.position < limit ), sX + ( self.position - self.scroll ), sY, self.focusedColour\
3978end\
3979\
3980\
3981configureConstructor({\
3982 orderedArguments = { \"X\", \"Y\", \"width\" },\
3983 argumentTypes = { value = \"string\", position = \"number\", selection = \"number\", placeholder = \"string\", placeholderColour = \"colour\", selectedColour = \"colour\", selectedBackgroundColour = \"colour\", limit = \"number\", mask = \"string\" },\
3984 useProxy = { \"toggled\" }\
3985}, true)\
3986",
3987["MAnimationManager.ti"]="class \"MAnimationManager\" abstract() {\
3988 animations = {};\
3989 animationTimer = false;\
3990\
3991 time = false;\
3992}\
3993\
3994--[[\
3995 @desc When the animation timer ticks, update animations attached to this application and requeue the timer if more animations must occur.\
3996]]\
3997function MAnimationManager:updateAnimations()\
3998 local dt = os.clock() - self.time\
3999\
4000 local anims, anim = self.animations\
4001 for i = #anims, 1, -1 do\
4002 anim = anims[ i ]\
4003\
4004 if anim:update( dt ) then\
4005 if type( anim.promise ) == \"function\" then\
4006 anim:promise( self )\
4007 end\
4008\
4009 self:removeAnimation( anim )\
4010 end\
4011 end\
4012\
4013 self.timer = false\
4014 if #anims > 0 then self:restartAnimationTimer() end\
4015end\
4016\
4017--[[\
4018 @instance\
4019 @desc Adds an animation to this object, on update this animation will be updated\
4020 @param <Tween - animation>\
4021]]\
4022function MAnimationManager:addAnimation( animation )\
4023 if not Titanium.typeOf( animation, \"Tween\", true ) then\
4024 return error(\"Failed to add animation to manager. '\"..tostring( animation )..\"' is invalid, Tween instance expected\")\
4025 end\
4026\
4027 self:removeAnimation( animation.name )\
4028 table.insert( self.animations, animation )\
4029\
4030 if not self.timer then\
4031 self:restartAnimationTimer()\
4032 end\
4033\
4034 return animation\
4035end\
4036\
4037--[[\
4038 @instance\
4039 @desc Removes an animation from this object, it will stop receiving updates from this object\
4040]]\
4041function MAnimationManager:removeAnimation( animation )\
4042 local searchName\
4043 if type( animation ) == \"string\" then\
4044 searchName = true\
4045 elseif not Titanium.typeOf( animation, \"Tween\", true ) then\
4046 return error(\"Failed to remove animation from manager. '\"..tostring( animation )..\"' is invalid, Tween instance expected\")\
4047 end\
4048\
4049 local anims = self.animations\
4050 for i = 1, #anims do\
4051 if ( searchName and anims[ i ].name == animation ) or ( not searchName and anims[ i ] == animation ) then\
4052 return table.remove( anims, i )\
4053 end\
4054 end\
4055end\
4056\
4057--[[\
4058 @instance\
4059 @desc When an animation is queued the timer is created for 'time' (0.05). This replaces the currently running timer (if any).\
4060 The objects 'time' is then updated to the current time (os.clock)\
4061 @param [number - time]\
4062]]\
4063function MAnimationManager:restartAnimationTimer( time )\
4064 if self.timer then\
4065 os.cancelTimer( self.timer )\
4066 end\
4067\
4068 self.time = os.clock()\
4069 self.timer = os.startTimer( type( time ) == \"number\" and time or .05 )\
4070end\
4071",
4072["Component.ti"]="--[[\
4073 A Component is an object that can be respresented visually.\
4074--]]\
4075\
4076class \"Component\" abstract() mixin \"MPropertyManager\" {\
4077 width = 1;\
4078 height = 1;\
4079 X = 1;\
4080 Y = 1;\
4081\
4082 changed = true;\
4083\
4084 backgroundChar = \" \";\
4085}\
4086\
4087function Component:queueAreaReset()\
4088 local parent = self.parent\
4089 if parent then\
4090 parent:redrawArea( self.X, self.Y, self.width, self.height )\
4091 end\
4092\
4093 self.changed = true\
4094end\
4095\
4096function Component:set( tbl )\
4097 if type( tbl ) ~= \"table\" then\
4098 return error \"Table expected\"\
4099 end\
4100\
4101 for property, value in pairs( tbl ) do\
4102 self[ property ] = value\
4103 end\
4104\
4105 return self\
4106end\
4107\
4108function Component:setX( X )\
4109 self:queueAreaReset()\
4110 self.X = X\
4111end\
4112\
4113function Component:setY( Y )\
4114 self:queueAreaReset()\
4115 self.Y = Y\
4116end\
4117\
4118function Component:setWidth( width )\
4119 self:queueAreaReset()\
4120\
4121 self.width = width\
4122 self.canvas.width = width\
4123end\
4124\
4125function Component:setHeight( height )\
4126 self:queueAreaReset()\
4127\
4128 self.height = height\
4129 self.canvas.height = height\
4130end\
4131\
4132function Component:setColour( colour )\
4133 self.colour = colour\
4134 self.canvas.colour = colour\
4135\
4136 self.changed = true\
4137end\
4138\
4139function Component:setBackgroundColour( backgroundColour )\
4140 self.backgroundColour = backgroundColour\
4141 self.canvas.backgroundColour = backgroundColour\
4142\
4143 self.changed = true\
4144end\
4145\
4146function Component:setTransparent( transparent )\
4147 self.transparent = transparent\
4148 self.canvas.transparent = transparent\
4149\
4150 self.changed = true\
4151end\
4152\
4153function Component:setBackgroundChar( backgroundChar )\
4154 if backgroundChar == \"nil\" then\
4155 backgroundChar = nil\
4156 end\
4157\
4158 self.backgroundChar = backgroundChar\
4159 self.canvas.backgroundChar = backgroundChar\
4160\
4161 self.changed = true\
4162end\
4163\
4164function Component:setBackgroundTextColour( backgroundTextColour )\
4165 self.backgroundTextColour = backgroundTextColour\
4166 self.canvas.backgroundTextColour = backgroundTextColour\
4167\
4168 self.changed = true\
4169end\
4170\
4171configureConstructor {\
4172 orderedArguments = { \"X\", \"Y\", \"width\", \"height\" },\
4173 argumentTypes = { X = \"number\", Y = \"number\", width = \"number\", height = \"number\", colour = \"colour\", backgroundColour = \"colour\", backgroundTextColour = \"colour\", transparent = \"boolean\" }\
4174} alias {\
4175 color = \"colour\",\
4176 backgroundColor = \"backgroundColour\"\
4177}\
4178",
4179["Titanium.lua"]="--[[\
4180 Event declaration\
4181 =================\
4182\
4183 Titanium needs to know what class types to spawn when an event is spawned, for flexibility this can be edited whenever you see fit. The matrix\
4184 starts blank, so we define basic events here. (on event type 'key', spawn instance of type 'value')\
4185]]\
4186Event.static.matrix = {\
4187 mouse_click = MouseEvent,\
4188 mouse_drag = MouseEvent,\
4189 mouse_up = MouseEvent,\
4190 mouse_scroll = MouseEvent,\
4191\
4192 key = KeyEvent,\
4193 key_up = KeyEvent,\
4194\
4195 char = CharEvent\
4196}\
4197\
4198--[[\
4199 Image Parsing\
4200 =============\
4201\
4202 Titaniums Image class parses image files based on their extension, two popular formats (nfp and default) are supported by default, however this can be expanded like you see here.\
4203 These functions are expected to return the dimensions of the image and, a buffer (2D table) of pixels to be drawn directly to the images canvas. Pixels that do not exist in the image\
4204 need not be acounted for, Titanium will automatically fill those as 'blank' pixels by setting them as 'transparent'.\
4205\
4206 See the default functions below for good examples of image parsing.\
4207]]\
4208\
4209Image.setImageParser(\"\", function( stream ) -- Default CC images, no extension\
4210 -- Break image into lines, find the maxwidth of the image (the length of the longest line)\
4211 local hex = TermCanvas.static.hex\
4212 width, lines, pixels = 1, {}, {}\
4213 for line in stream:gmatch \"([^\\n]*)\\n?\" do\
4214 width = math.max( width, #line )\
4215 lines[ #lines + 1 ] = line\
4216 end\
4217\
4218 -- Iterate each line, forming a buffer of pixels with missing information (whitespace) being left nil\
4219 for l = 1, #lines do\
4220 local y, line = width * ( l - 1 ), lines[ l ]\
4221\
4222 for i = 1, width do\
4223 local colour = hex[ line:sub( i, i ) ]\
4224 pixels[ y + i ] = { \" \", colour, colour }\
4225 end\
4226 end\
4227\
4228 return width, #lines, pixels\
4229end).setImageParser(\"nfp\", function( stream ) -- NFP images, .nfp extension\
4230 --TODO: Look into nfp file format and write parser\
4231end)\
4232\
4233--[[\
4234 Tween setup\
4235 ===========\
4236\
4237 The following blocks of code define the functions that will be invoked when an animation that used that type of easing is updated. These functions\
4238 are adjusted versions (the algorithm has remained the same, however code formatting and variable names are largely changed to match Titanium) of\
4239 the easing functions published by kikito on GitHub. Refer to 'LICENSE' in this project root for more information (and Enrique's license).\
4240\
4241 The functions are passed 4 arguments, these arguments are listed below:\
4242 - clock: This argument contains the current clock time of the Tween being updated, this is used to tell how far through the animation we are (in seconds)\
4243 - initial: The value of the property being animated at the instantiation of the tween. This is usually added as a Y-Axis transformation.\
4244 - change: The difference of the initial and final property value. ie: How much the value will have to change to match the final from where it was as instantiation.\
4245 - duration: The total duration of the running Tween.\
4246\
4247 Certain functions are passed extra arguments. The Tween class doesn't pass these in, however custom animation engines could invoke these easing functions\
4248 through `Tween.static.easing.<easingType>`.\
4249]]\
4250\
4251local abs, pow, asin, sin, sqrt, pi = math.abs, math.pow, math.asin, math.sin, math.sqrt, math.pi\
4252local easing = Tween.static.easing\
4253-- Linear easing function\
4254Tween.addEasing(\"linear\", function( clock, initial, change, duration )\
4255 return change * clock / duration + initial\
4256end)\
4257\
4258-- Quad easing functions\
4259Tween.addEasing(\"inQuad\", function( clock, initial, change, duration )\
4260 return change * pow( clock / duration, 2 ) + initial\
4261end).addEasing(\"outQuad\", function( clock, initial, change, duration )\
4262 local clock = clock / duration\
4263 return -change * clock * ( clock - 2 ) + initial\
4264end).addEasing(\"inOutQuad\", function( clock, initial, change, duration )\
4265 local clock = clock / duration * 2\
4266 if clock < 1 then\
4267 return change / 2 * pow( clock, 2 ) + initial\
4268 end\
4269\
4270 return -change / 2 * ( ( clock - 1 ) * ( clock - 3 ) - 1 ) + initial\
4271end).addEasing(\"outInQuad\", function( clock, initial, change, duration )\
4272 if clock < duration / 2 then\
4273 return easing.outQuad( clock * 2, initial, change / 2, duration )\
4274 end\
4275\
4276 return easing.inQuad( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration)\
4277end)\
4278\
4279-- Cubic easing functions\
4280Tween.addEasing(\"inCubic\", function( clock, initial, change, duration )\
4281 return change * pow( clock / duration, 3 ) + initial\
4282end).addEasing(\"outCubic\", function( clock, initial, change, duration )\
4283 return change * ( pow( clock / duration - 1, 3 ) + 1 ) + initial\
4284end).addEasing(\"inOutCubic\", function( clock, initial, change, duration )\
4285 local clock = clock / duration * 2\
4286 if clock < 1 then\
4287 return change / 2 * clock * clock * clock + initial\
4288 end\
4289\
4290 clock = clock - 2\
4291 return change / 2 * (clock * clock * clock + 2) + initial\
4292end).addEasing(\"outInCubic\", function( clock, initial, change, duration )\
4293 if clock < duration / 2 then\
4294 return easing.outCubic( clock * 2, initial, change / 2, duration )\
4295 end\
4296\
4297 return easing.inCubic( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4298end)\
4299\
4300-- Quart easing functions\
4301Tween.addEasing(\"inQuart\", function( clock, initial, change, duration )\
4302 return change * pow( clock / duration, 4 ) + initial\
4303end).addEasing(\"outQuart\", function( clock, initial, change, duration )\
4304 return -change * ( pow( clock / duration - 1, 4 ) - 1 ) + initial\
4305end).addEasing(\"inOutQuart\", function( clock, initial, change, duration )\
4306 local clock = clock / duration * 2\13\
4307 if clock < 1 then\13\
4308 return change / 2 * pow(clock, 4) + initial\13\
4309 end\13\
4310\13\
4311 return -change / 2 * ( pow( clock - 2, 4 ) - 2 ) + initial\
4312end).addEasing(\"outInQuart\", function( clock, initial, change, duration )\
4313 if clock < duration / 2 then\13\
4314 return easing.outQuart( clock * 2, initial, change / 2, duration )\13\
4315 end\13\
4316\13\
4317 return easing.inQuart( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4318end)\
4319\
4320-- Quint easing functions\
4321Tween.addEasing(\"inQuint\", function( clock, initial, change, duration )\
4322 return change * pow( clock / duration, 5 ) + initial\
4323end).addEasing(\"outQuint\", function( clock, initial, change, duration )\
4324 return change * ( pow( clock / duration - 1, 5 ) + 1 ) + initial\
4325end).addEasing(\"inOutQuint\", function( clock, initial, change, duration )\
4326 local clock = clock / duration * 2\
4327 if clock < 1 then\
4328 return change / 2 * pow( clock, 5 ) + initial\
4329 end\
4330\
4331 return change / 2 * (pow( clock - 2, 5 ) + 2 ) + initial\
4332end).addEasing(\"outInQuint\", function( clock, initial, change, duration )\
4333 if clock < duration / 2 then\
4334 return easing.outQuint( clock * 2, initial, change / 2, duration )\
4335 end\
4336\
4337 return easing.inQuint( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4338end)\
4339\
4340-- Sine easing functions\
4341Tween.addEasing(\"inSine\", function( clock, initial, change, duration )\
4342 return -change * cos( clock / duration * ( pi / 2 ) ) + change + initial\
4343end).addEasing(\"outSine\", function( clock, initial, change, duration )\
4344 return change * sin( clock / duration * ( pi / 2 ) ) + initial\
4345end).addEasing(\"inOutSine\", function( clock, initial, change, duration )\
4346 return -change / 2 * ( cos( pi * clock / duration ) - 1 ) + initial\
4347end).addEasing(\"outInSine\", function( clock, initial, change, duration )\
4348 if clock < duration / 2 then\
4349 return easing.outSine( clock * 2, initial, change / 2, duration )\
4350 end\
4351\
4352 return easing.inSine( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4353end)\
4354\
4355-- Expo easing functions\
4356Tween.addEasing(\"inExpo\", function( clock, initial, change, duration )\
4357 if clock == 0 then\
4358 return initial\
4359 end\
4360 return change * pow( 2, 10 * ( clock / duration - 1 ) ) + initial - change * 0.001\
4361end).addEasing(\"outExpo\", function( clock, initial, change, duration )\
4362 if clock == duration then\
4363 return initial + change\
4364 end\
4365\
4366 return change * 1.001 * ( -pow( 2, -10 * clock / duration ) + 1 ) + initial\
4367end).addEasing(\"inOutExpo\", function( clock, initial, change, duration )\
4368 if clock == 0 then\
4369 return initial\
4370 elseif clock == duration then\
4371 return initial + change\
4372 end\
4373\
4374 local clock = clock / duration * 2\
4375 if clock < 1 then\
4376 return change / 2 * pow( 2, 10 * ( clock - 1 ) ) + initial - change * 0.0005\
4377 end\
4378\
4379 return change / 2 * 1.0005 * ( -pow( 2, -10 * ( clock - 1 ) ) + 2 ) + initial\
4380end).addEasing(\"outInExpo\", function( clock, initial, change, duration )\
4381 if clock < duration / 2 then\
4382 return easing.outExpo( clock * 2, initial, change / 2, duration )\
4383 end\
4384\
4385 return easing.inExpo( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4386end)\
4387\
4388-- Circ easing functions\
4389Tween.addEasing(\"inCirc\", function( clock, initial, change, duration )\
4390 return -change * ( sqrt( 1 - pow( clock / duration, 2 ) ) - 1 ) + initial\
4391end).addEasing(\"outCirc\", function( clock, initial, change, duration )\
4392 return change * sqrt( 1 - pow( clock / duration - 1, 2 ) ) + initial\
4393end).addEasing(\"inOutCirc\", function( clock, initial, change, duration )\
4394 local clock = clock / duration * 2\
4395 if clock < 1 then\
4396 return -change / 2 * ( sqrt( 1 - clock * clock ) - 1 ) + initial\
4397 end\
4398\
4399 clock = clock - 2\
4400 return change / 2 * ( sqrt( 1 - clock * clock ) + 1 ) + initial\
4401end).addEasing(\"outInCirc\", function( clock, initial, change, duration )\
4402 if clock < duration / 2 then\
4403 return easing.outCirc( clock * 2, initial, change / 2, duration )\
4404 end\
4405\
4406 return easing.inCirc( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4407end)\
4408\
4409-- Elastic easing functions\
4410local function calculatePAS(p,a,change,duration)\
4411 local p, a = p or duration * 0.3, a or 0\
4412 if a < abs( change ) then\
4413 return p, change, p / 4 -- p, a, s\
4414 end\
4415\
4416 return p, a, p / ( 2 * pi ) * asin( change / a ) -- p,a,s\
4417end\
4418\
4419Tween.addEasing(\"inElastic\", function( clock, initial, change, duration, amplitude, period )\
4420 if clock == 0 then return initial end\
4421\
4422 local clock, s = clock / duration\
4423 if clock == 1 then\
4424 return initial + change\
4425 end\
4426\
4427 clock, p, a, s = clock - 1, calculatePAS( p, a, change, duration )\
4428 return -( a * pow( 2, 10 * clock ) * sin( ( clock * duration - s ) * ( 2 * pi ) / p ) ) + initial\
4429end).addEasing(\"outElastic\", function( clock, initial, change, duration, amplitude, period )\
4430 if clock == 0 then\
4431 return initial\
4432 end\
4433 local clock, s = clock / duration\
4434\
4435 if clock == 1 then\
4436 return initial + change\
4437 end\
4438\
4439 local p,a,s = calculatePAS( period, amplitude, change, duration )\
4440 return a * pow( 2, -10 * clock ) * sin( ( clock * duration - s ) * ( 2 * pi ) / p ) + change + initial\
4441end).addEasing(\"inOutElastic\", function( clock, initial, change, duration, amplitude, period )\
4442 if clock == 0 then return initial end\
4443\
4444 local clock = clock / duration * 2\
4445 if clock == 2 then return initial + change end\
4446\
4447 local clock, p, a, s = clock - 1, calculatePAS( period, amplitude, change, duration )\
4448 if clock < 0 then\
4449 return -0.5 * ( a * pow( 2, 10 * clock ) * sin( ( clock * duration - s ) * ( 2 * pi ) / p ) ) + initial\
4450 end\
4451\
4452 return a * pow( 2, -10 * clock ) * sin( ( clock * duration - s ) * ( 2 * pi ) / p ) * 0.5 + change + initial\
4453end).addEasing(\"outInElastic\", function( clock, initial, change, duration, amplitude, period )\
4454 if clock < duration / 2 then\
4455 return easing.outElastic( clock * 2, initial, change / 2, duration, amplitude, period )\
4456 end\
4457\
4458 return easing.inElastic( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration, amplitude, period )\
4459end)\
4460\
4461-- Back easing functions\
4462Tween.addEasing(\"inBack\", function( clock, initial, change, duration, s )\
4463 local s, clock = s or 1.70158, clock / duration\
4464\
4465 return change * clock * clock * ( ( s + 1 ) * clock - s ) + initial\
4466end).addEasing(\"outBack\", function( clock, initial, change, duration, s )\
4467 local s, clock = s or 1.70158, clock / duration - 1\
4468\
4469 return change * ( clock * clock * ( ( s + 1 ) * clock + s ) + 1 ) + initial\
4470end).addEasing(\"inOutBack\", function( clock, initial, change, duration, s )\
4471 local s, clock = ( s or 1.70158 ) * 1.525, clock / duration * 2\
4472 if clock < 1 then\
4473 return change / 2 * ( clock * clock * ( ( s + 1 ) * clock - s ) ) + initial\
4474 end\
4475\
4476 clock = clock - 2\
4477 return change / 2 * ( clock * clock * ( ( s + 1 ) * clock + s ) + 2 ) + initial\
4478end).addEasing(\"outInBack\", function( clock, initial, change, duration, s )\
4479 if clock < duration / 2 then\
4480 return easing.outBack( clock * 2, initial, change / 2, duration, s )\
4481 end\
4482\
4483 return easing.inBack( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration, s )\
4484end)\
4485\
4486-- Bounce easing functions\
4487Tween.addEasing(\"inBounce\", function( clock, initial, change, duration )\
4488 return change - easing.outBounce( duration - clock, 0, change, duration ) + initial\
4489end).addEasing(\"outBounce\", function( clock, initial, change, duration )\
4490 local clock = clock / duration\
4491 if clock < 1 / 2.75 then\
4492 return change * ( 7.5625 * clock * clock ) + initial\
4493 elseif clock < 2 / 2.75 then\
4494 clock = clock - ( 1.5 / 2.75 )\
4495 return change * ( 7.5625 * clock * clock + 0.75 ) + initial\
4496 elseif clock < 2.5 / 2.75 then\
4497 clock = clock - ( 2.25 / 2.75 )\
4498 return change * ( 7.5625 * clock * clock + 0.9375 ) + initial\
4499 end\
4500\
4501 clock = clock - (2.625 / 2.75)\
4502 return change * (7.5625 * clock * clock + 0.984375) + initial\
4503end).addEasing(\"inOutBounce\", function( clock, initial, change, duration )\
4504 if clock < duration / 2 then\
4505 return easing.inBounce( clock * 2, 0, change, duration ) * 0.5 + initial\
4506 end\
4507\
4508 return easing.outBounce( clock * 2 - duration, 0, change, duration ) * 0.5 + change * .5 + initial\
4509end).addEasing(\"outInBounce\", function( clock, initial, change, duration )\
4510 if clock < duration / 2 then\
4511 return easing.outBounce( clock * 2, initial, change / 2, duration )\
4512 end\
4513\
4514 return easing.inBounce( ( clock * 2 ) - duration, initial + change / 2, change / 2, duration )\
4515end)\
4516",
4517["CharEvent.ti"]="class \"CharEvent\" extends \"Event\" {\
4518 main = \"CHAR\";\
4519 char = false;\
4520}\
4521\
4522function CharEvent:__init__( name, char )\
4523 self.name = name\
4524 self.char = char\
4525\
4526 self.data = { name, char }\
4527end\
4528",
4529["Container.ti"]="class \"Container\" extends \"Node\" mixin \"MNodeContainer\" {\
4530 allowMouse = true;\
4531 allowKey = true;\
4532 allowChar = true;\
4533\
4534 consumeAll = true;\
4535}\
4536\
4537--[[\
4538 @instance\
4539 @desc Constructs the Container node with the value passed. If a nodes table is passed each entry inside of it will be added to the container as a node\
4540 @param [number - X], [number - Y], [number - width], [number - height], [table - nodes]\
4541]]\
4542function Container:__init__( ... )\
4543 self:resolve( ... )\
4544\
4545 local toset = self.nodes\
4546 self.nodes = {}\
4547\
4548 if type( toset ) == \"table\" then\
4549 for i = 1, #toset do\
4550 self:addNode( toset[ i ] )\
4551 end\
4552 end\
4553\
4554 self:super()\
4555end\
4556\
4557--[[\
4558 @instance\
4559 @desc Returns true if the node given is visible inside of the container\
4560 @param <Node - node>, [number - width], [number - height]\
4561 @return <boolean - visible>\
4562]]\
4563function Container:isNodeInBounds( node, width, height )\
4564 local left, top = node.X, node.Y\
4565\
4566 return not ( ( left + node.width ) < 1 or left > ( width or self.width ) or top > ( height or self.height ) or ( top + node.height ) < 1 )\
4567end\
4568\
4569--[[\
4570 @instance\
4571 @desc Draws contained nodes to container canvas. Nodes are only drawn if they are visible inside the container\
4572 @param [boolean - force], [number - offsetX], [number - offsetY]\
4573]]\
4574function Container:draw( force, offsetX, offsetY )\
4575 if self.changed or force then\
4576 local canvas = self.canvas\
4577\
4578 local width, height = self.width, self.height\
4579 local nodes, node = self.nodes\
4580 local offsetX, offsetY = offsetX or 0, offsetY or 0\
4581\
4582 for i = 1, #nodes do\
4583 node = nodes[ i ]\
4584\
4585 if node.needsRedraw and node.visible then\
4586 node:draw( force )\
4587\
4588 node.canvas:drawTo( canvas, node.X + offsetX, node.Y + offsetY )\
4589 node.needsRedraw = false\
4590 end\
4591 end\
4592\
4593 self.changed = false\
4594 end\
4595end\
4596\
4597--[[\
4598 @instance\
4599 @desc Redirects all events to child nodes. Mouse events are adjusted to become relative to this container. Event handlers on Container are still fired if present\
4600 @param <Event - event>\
4601 @return <boolean - propagate>\
4602]]\
4603function Container:handle( eventObj )\
4604 if not self.super:handle( eventObj ) then return end\
4605\
4606 local clone\
4607 if eventObj.main == \"MOUSE\" then\
4608 clone = eventObj:clone( self )\
4609 clone.isWithin = clone.isWithin and eventObj:withinParent( self ) or false\
4610 end\
4611\
4612 self:shipEvent( clone or eventObj )\
4613 if clone and clone.isWithin and ( self.consumeAll or clone.handled ) then\
4614 eventObj.handled = true\
4615 end\
4616 return true\
4617end\
4618\
4619function Container:shipEvent( event )\
4620 local nodes = self.nodes\
4621 for i = #nodes, 1, -1 do\
4622 nodes[ i ]:handle( event )\
4623 end\
4624end\
4625\
4626function Container:setWidth( width )\
4627\9self.super:setWidth( width )\
4628\9local nodes = self.nodes\
4629\9for i = 1, #nodes do\
4630\9\9nodes[i].needsRedraw = true\
4631\9end\
4632end\
4633\
4634function Container:setHeight( height )\
4635\9self.super:setHeight( height )\
4636\9local nodes = self.nodes\
4637\9for i = 1, #nodes do\
4638\9\9nodes[i].needsRedraw = true\
4639\9end\
4640end\
4641\
4642\
4643configureConstructor({\
4644 orderedArguments = { \"X\", \"Y\", \"width\", \"height\", \"nodes\", \"backgroundColour\" },\
4645 argumentTypes = {\
4646 nodes = \"table\"\
4647 }\
4648}, true)\
4649",
4650["PageContainer.ti"]="--[[\
4651 The PageContainer serves as a container that shows one 'page' at a time. Preset (or completely custom) animated transitions can be used when\
4652 a new page is selected.\
4653]]\
4654\
4655class \"PageContainer\" extends \"Container\" {\
4656 scroll = 0;\
4657\
4658 animationDuration = 0.25;\
4659 animationEasing = \"outQuad\";\
4660 customAnimation = false;\
4661 selectedPage = false;\
4662\
4663 pageIndexes = {};\
4664}\
4665\
4666--[[\
4667 @instance\
4668 @desc Intercepts the draw call, adding the x scroll to the x offset\
4669 @param [boolean - force], [number - offsetX], [number - offsetY]\
4670]]\
4671function PageContainer:draw( force, offsetX, offsetY )\
4672 return self.super:draw( force, ( offsetX or 0 ) - self.scroll, offsetY )\
4673end\
4674\
4675--[[\
4676 @instance\
4677 @desc If a MOUSE event is handled, it's X co-ordinate is adjusted using the scroll offset of the page container.\
4678 @param <Event Instance - eventObj>\
4679 @return <boolean - propagate>\
4680]]\
4681function PageContainer:handle( eventObj )\
4682 if not self.super.super:handle( eventObj ) then return end\
4683\
4684 local clone\
4685 if eventObj.main == \"MOUSE\" then\
4686 clone = eventObj:clone( self )\
4687 clone.X = clone.X + self.scroll\
4688 clone.isWithin = clone.isWithin and eventObj:withinParent( self ) or false\
4689 end\
4690\
4691 self:shipEvent( clone or eventObj )\
4692 if clone and clone.isWithin and ( self.consumeAll or clone.handled ) then\
4693 eventObj.handled = true\
4694 end\
4695 return true\
4696end\
4697\
4698--[[\
4699 @instance\
4700 @desc Selects the new page using the 'pageID'. If a function is given as argument #2 'animationOverride', it will be called instead of the customAnimation set (or the default animation method used).\
4701 Therefore the animationOverride is given full control of the transition, allowing for easy one-off transition effects.\
4702\
4703 If 'customAnimation' is set on the instance, it will be called if no 'animationOverride' is provided, providing a more long term override method.\
4704\
4705 If neither are provided, a normal animation will take place, using 'animationDuration' and 'animationEasing' set on the instance as parameters for the animation.\
4706 @param <string - pageID>, [function - animationOverride]\
4707]]\
4708function PageContainer:selectPage( pageID, animationOverride )\
4709 local page = self:getPage( pageID )\
4710\
4711 self.selectedPage = page\
4712 if type( animationOverride ) == \"function\" then\
4713 return animationOverride( self.currentPage, page )\
4714 elseif self.customAnimation then\
4715 return self.customAnimation( self.currentPage, page )\
4716 end\
4717\
4718 self:animate( self.__ID .. \"_PAGE_CONTAINER_SELECTION\", \"scroll\", ( self:getPagePosition( pageID ) - 1 ) * self.width, self.animationDuration, self.animationEasing )\
4719end\
4720\
4721--[[\
4722 @instance\
4723 @desc Returns an integer representing the position of the page. These may change as pages are added and removed from the PageContainer - don't rely on them remaining constant\
4724 @param <string - pageID>\
4725 @return <number - position>\
4726]]\
4727function PageContainer:getPagePosition( pageID )\
4728 local indexes = self.pageIndexes\
4729 for i = 1, #indexes do\
4730 if indexes[ i ] == pageID then\
4731 return i\
4732 end\
4733 end\
4734end\
4735\
4736--[[\
4737 @instance\
4738 @desc Ensures the node being added to the PageContainer is a 'Page' node because no other nodes should be added directly to this node\
4739 @param <Page Instance - node>\
4740 @return 'param1 (node)'\
4741]]\
4742function PageContainer:addNode( node )\
4743 if Titanium.typeOf( node, \"Page\", true ) then\
4744 local pgInd = self.pageIndexes\
4745 if self:getPagePosition( node.id ) then\
4746 return error(\"Cannot add page '\"..tostring( node )..\"'. Another page with the same ID already exists inside this PageContainer\")\
4747 end\
4748\
4749 pgInd[ #pgInd + 1 ] = node.id\
4750 node.X = ( #pgInd - 1 ) * self.width + 1\
4751\
4752 return self.super:addNode( node )\
4753 end\
4754\
4755 return error(\"Only 'Page' nodes can be added as direct children of 'PageContainer' nodes, '\"..tostring( node )..\"' is invalid\")\
4756end\
4757\
4758--[[\
4759 @instance\
4760 @desc A alias \"for\" 'addNode', contextualized for the PageContainer\
4761 @param <Page Instance - page>\
4762 @return 'param1 (page)'\
4763]]\
4764function PageContainer:addPage( page )\
4765 return self:addNode( page )\
4766end\
4767\
4768--[[\
4769 @instance\
4770 @desc A alias \"for\" 'getNode', contextualized for the PageContainer\
4771 @param <string - id>, [boolean - recursive]\
4772 @return [Node Instance - node]\
4773]]\
4774function PageContainer:getPage( ... )\
4775 return self:getNode( ... )\
4776end\
4777\
4778--[[\
4779 @instance\
4780 @desc A alias \"for\" 'removeNode', contextualized for the PageContainer\
4781 @param <Node Instance | string - id>\
4782 @return <boolean - success>, [node - removedNode]\
4783]]\
4784function PageContainer:removePage( ... )\
4785 return self:removeNode( ... )\
4786end\
4787\
4788--[[\
4789 @instance\
4790 @desc Shifts requests to clear the PageContainer area to the left, depending on the scroll position of the container\
4791 @param <number - x>, <number - y>, <number - width>, <number - height>\
4792]]\
4793function PageContainer:redrawArea( x, y, width, height )\
4794 self.super:redrawArea( x, y, width, height, -self.scroll )\
4795end\
4796\
4797--[[\
4798 @instance\
4799 @desc Due to the contents of the PageContainer not actually moving (just the scroll), the content of the PageContainer must be manually cleared.\
4800 To fit this demand, the area of the PageContainer is cleared when the scroll parameter is changed.\
4801]]\
4802function PageContainer:setScroll( scroll )\
4803 self.scroll = scroll\
4804 self:redrawArea( 1, 1, self.width, self.height )\
4805end\
4806",
4807["Canvas.ti"]="--[[\
4808 The Canvas object is used by all components. It facilitates the drawing of pixels which are stored in its buffer.\
4809\
4810 The Canvas object is abstract. If you need a canvas for your object 'NodeCanvas' and 'TermCanvas' are provided with Titanium and may suite your needs.\
4811--]]\
4812\
4813local function range( xBoundary, xDesired, width, canvasWidth )\
4814 local x1 = xBoundary > xDesired and 1 - xDesired or 1\
4815 local x2 = xDesired + width > canvasWidth and canvasWidth - xDesired or width\
4816\
4817 return x1, x2\
4818end\
4819\
4820class \"Canvas\" abstract() {\
4821 buffer = {};\
4822 last = {};\
4823\
4824 width = 51;\
4825 height = 19;\
4826\
4827 backgroundColour = 32768;\
4828 colour = 1;\
4829\
4830 transparent = false;\
4831}\
4832\
4833--[[\
4834 @constructor\
4835 @desc Constructs the canvas instance and binds it with the owner supplied.\
4836 @param <ClassInstance - owner>\
4837]]\
4838function Canvas:__init__( owner )\
4839 self.raw.owner = Titanium.isInstance( owner ) and owner or error(\"Invalid argument for Canvas. Expected instance owner, got '\"..tostring( owner )..\"'\")\
4840 self.raw.width = owner.raw.width\
4841 self.raw.height = owner.raw.height\
4842\
4843 self.raw.colour = owner.raw.colour\
4844 self.raw.backgroundChar = owner.raw.backgroundChar\
4845 if self.raw.backgroundChar == \"nil\" then\
4846 self.raw.backgroundChar = nil\
4847 end\
4848 self.raw.backgroundTextColour = owner.raw.backgroundTextColour\
4849 self.raw.backgroundColour = owner.raw.backgroundColour\
4850\
4851 self:clear()\
4852end\
4853\
4854--[[\
4855 @instance\
4856 @desc Replaces the canvas with a blank one\
4857 @param [number - colour]\
4858]]\
4859function Canvas:clear( colour )\
4860 local pixel, buffer = { not self.transparent and self.backgroundChar, self.colour, self.transparent and 0 or colour or self.backgroundColour }, self.buffer\
4861\
4862 for index = 1, self.width * self.height do\
4863 buffer[ index ] = pixel\
4864 end\
4865end\
4866\
4867--[[\
4868 @instance\
4869 @desc Clears an area of the canvas defined by the arguments provided.\
4870 @param <number - areaX>, <number - areaY>, <number - areaWidth>, <number - areaHeight>, [number - colour]\
4871]]\
4872function Canvas:clearArea( aX, aY, aWidth, aHeight, colour )\
4873 local aY, aX, cWidth = aY > 0 and aY - 1 or 0, aX > 0 and aX - 1 or 0, self.width\
4874 local pixel, buffer = { not self.transparent and self.backgroundChar, self.colour, self.transparent and 0 or colour or self.backgroundColour }, self.buffer\
4875\
4876 local xBoundary, yBoundary = cWidth - aX, self.height\
4877 local effectiveWidth = xBoundary < aWidth and xBoundary or aWidth\
4878 for y = 0, -1 + ( aHeight < yBoundary and aHeight or yBoundary ) do\
4879 local pos = aX + ( y + aY ) * cWidth\
4880 for x = 1, effectiveWidth do\
4881 buffer[ pos + x ] = pixel\
4882 end\
4883 end\
4884end\
4885\
4886--[[\
4887 @instance\
4888 @desc Updates the transparency setting of the canvas and then clears the canvas to apply this setting\
4889 @param <number - colour>\
4890]]\
4891function Canvas:setTransparent( transparent )\
4892 self.transparent = transparent\
4893 self:clear()\
4894end\
4895\
4896--[[\
4897 @instance\
4898 @desc Updates the colour of the canvas and then clears the canvas\
4899 @param <number - colour>\
4900]]\
4901function Canvas:setColour( colour )\
4902 self.colour = colour\
4903 self:clear()\
4904end\
4905\
4906--[[\
4907 @instance\
4908 @desc Updates the background colour of the canvas and then clears the canvas\
4909 @param <number - backgroundColour>\
4910]]\
4911function Canvas:setBackgroundColour( backgroundColour )\
4912 self.backgroundColour = backgroundColour\
4913 self:clear()\
4914end\
4915\
4916--[[\
4917 @instance\
4918 @desc Updates the background character to be used when clearing the canvas. Clears the canvas to apply the change\
4919 @param <string/false/nil - char>\
4920]]\
4921function Canvas:setBackgroundChar( char )\
4922 self.backgroundChar = char\
4923 self:clear()\
4924end\
4925\
4926function Canvas:setWidth( width )\
4927\9self.width = width\
4928\9self:clear()\
4929end\
4930\
4931function Canvas:setHeight( height )\
4932\9self.height = height\
4933\9self:clear()\
4934end\
4935\
4936--[[\
4937 @instance\
4938 @desc Draws the canvas to the target 'canvas' using the X and Y offsets. Pixels that are marked transparent are not drawn.\
4939 @param <Canvas - canvas>, [number - offsetX], [number - offsetY]\
4940]]\
4941function Canvas:drawTo( canvas, offsetX, offsetY )\
4942 local offsetX = offsetX - 1 or 0\
4943 local offsetY = offsetY - 1 or 0\
4944\
4945 local sRaw, tRaw = self.raw, canvas.raw\
4946 local width, height, buffer = sRaw.width, sRaw.height, sRaw.buffer\
4947 local tWidth, tHeight, tBuffer = tRaw.width, tRaw.height, tRaw.buffer\
4948\
4949 local colour, backgroundColour, backgroundTextColour = sRaw.colour, sRaw.backgroundColour, sRaw.backgroundTextColour\
4950 local xStart, xEnd = range( 1, offsetX, width, tWidth )\
4951\
4952 local cache, tCache, top, tc, tf, tb, bot, bc, bf, bb, tPos = 0, offsetX + ( offsetY * tWidth )\
4953 for y = 1, height do\
4954 local cY = y + offsetY\
4955 if cY >= 1 and cY <= tHeight then\
4956 for x = xStart, xEnd do\
4957 top = buffer[ cache + x ]\
4958 tc, tf, tb, tPos = top[ 1 ], top[ 2 ], top[ 3 ], tCache + x\
4959 bot = tBuffer[ tPos ]\
4960 bc, bf, bb = bot[ 1 ], bot[ 2 ], bot[ 3 ]\
4961\
4962 if tc and ( tf and tf ~= 0 ) and ( tb and tb ~= 0 ) then\
4963 tBuffer[ tPos ] = top\
4964 elseif not tc and tf == 0 and tb == 0 and bc and bf ~= 0 and bb ~= 0 then\
4965 tBuffer[ tPos ] = bot\
4966 else\
4967 local nc, nf, nb = tc or bc, tf or colour, tb or backgroundColour\
4968\
4969 if not tc then\
4970 nf = backgroundTextColour or bf\
4971 end\
4972\
4973 tBuffer[ tPos ] = { nc, nf == 0 and bf or nf, nb == 0 and bb or nb }\
4974 end\
4975 end\
4976 elseif cY > tHeight then\
4977 break\
4978 end\
4979\
4980 cache = cache + width\
4981 tCache = tCache + tWidth\
4982 end\
4983end\
4984",
4985["ContextMenu.ti"]="--[[\
4986 The ContextMenu class \"allows\" developers to dynamically spawn context menus with content they can customize. This node takes the application bounds into account and ensures\
4987 the content doesn't spill out of view.\
4988--]]\
4989class \"ContextMenu\" extends \"Container\" {\
4990 static = {\
4991 allowedTypes = { \"Button\", \"Label\" }\
4992 };\
4993}\
4994\
4995--[[\
4996 @constructor\
4997 @desc Resolves constructor arguments and invokes super. The canvas of this node is also marked transparent, as the canvas of this node is a rectangular shape surrounding all subframes.\
4998 @param <table - structure>*\
4999\
5000 Note: Ordered arguments inherited from other classes not included\
5001]]\
5002function ContextMenu:__init__( ... )\
5003 self:resolve( ... )\
5004 self:super()\
5005\
5006 self.transparent = true\
5007end\
5008\
5009--[[\
5010 @instance\
5011 @desc Population of the context menu requires a parent to be present. Therefore, when the parent is set on a node we will populate the\
5012 context menu, instead of at instantiation\
5013 @param <Node - parent>\
5014]]\
5015function ContextMenu:setParent( parent )\
5016 self.parent = parent\
5017\
5018 if parent then\
5019 local frame = self:addNode( ScrollContainer() )\
5020 frame.frameID = 1\
5021\
5022 self:populate( frame, self.structure )\
5023 frame.visible = true\
5024 end\
5025end\
5026\
5027--[[\
5028 @instance\
5029 @desc Populates the context menu with the options specified in the 'structure' table.\
5030 Accounts for application edge by positioning the menu as to avoid the menu contents spilling out of view.\
5031 @param <MNodeContainer* - parent>, <table - structure>\
5032\
5033 Note: The 'parent' param must be a node that can contain other nodes.\
5034]]\
5035function ContextMenu:populate( frame, structure )\
5036 local queue, q, totalWidth, totalHeight, negativeX = { { frame, structure } }, 1, 0, 0, 1\
5037\
5038 while q <= #queue do\
5039 local menu, structure, width = queue[ q ][ 1 ], queue[ q ][ 2 ], 0\
5040 local rules, Y = {}, 0\
5041\
5042 for i = 1, #structure do\
5043 Y = Y + 1\
5044 local part = structure[ i ]\
5045 local partType = part[ 1 ]:lower()\
5046\
5047 if partType == \"custom\" then\
5048 --TODO: Custom menu entries\
5049 else\
5050 if partType == \"menu\" then\
5051 local subframe = self:addNode( ScrollContainer( nil, menu.Y + Y - 1 ) )\
5052 if not menu.subframes then\
5053 menu.subframes = { subframe }\
5054 else\
5055 table.insert( menu.subframes, subframe )\
5056 end\
5057\
5058 subframe.visible = false\
5059\
5060 local id = #self.nodes\
5061 subframe.frameID = id\
5062 menu:addNode( Button( part[ 2 ], 1, Y ):on( \"trigger\", function()\
5063 local subframes = menu.subframes\
5064 for i = 1, #subframes do\
5065 if subframes[ i ] ~= subframe and subframes[ i ].visible then\
5066 self:closeFrame( subframes[ i ].frameID )\
5067 end\
5068 end\
5069\
5070 if subframe.visible then\
5071 self:closeFrame( id )\
5072 else\
5073 subframe.visible = true\
5074 end\
5075 end ) )\
5076\
5077 table.insert( queue, { subframe, part[ 3 ], menu } )\
5078 elseif partType == \"rule\" then\
5079 rules[ #rules + 1 ] = Y\
5080 elseif partType == \"button\" then\
5081 menu:addNode( Button( part[ 2 ], 1, Y ):on( \"trigger\", part[ 3 ] ) )\
5082 elseif partType == \"label\" then\
5083 menu:addNode( Label( part[ 2 ], 1, Y ) )\
5084 end\
5085\
5086 if partType ~= \"rule\" then\
5087 width = math.max( width, #part[ 2 ] )\
5088 end\
5089 end\
5090 end\
5091\
5092 if width == 0 then error \"Failed to populate context menu. Content given has no detectable width (or zero). Cannot proceed without width greater than 0\" end\
5093\
5094 for n = 1, #menu.nodes do menu.nodes[ n ].width = width end\
5095 for r = 1, #rules do menu:addNode( Label( (\"-\"):rep( width ), 1, rules[ r ] ) ) end\
5096\
5097 local parentMenu, widthOffset, relX = queue[ q ][ 3 ], 0, 0\
5098 if parentMenu then\
5099 widthOffset, relX = parentMenu.width, parentMenu.X\
5100 end\
5101\
5102 local spill = ( relX + widthOffset + width + self.X - 1 ) - self.parent.width\
5103 if spill > 0 then\
5104 menu.X = relX - ( parentMenu and width or spill )\
5105 else\
5106 menu.X = relX + widthOffset\
5107 end\
5108 negativeX = math.min( negativeX, menu.X )\
5109\
5110 menu.width, menu.height = width, Y - math.max( menu.Y + Y - self.parent.height, 0 )\
5111 menu:cacheContent()\
5112\
5113 totalWidth, totalHeight = totalWidth + menu.width, totalHeight + math.max( menu.height - ( parentMenu and parentMenu.Y or 0 ), 1 )\
5114 q = q + 1\
5115 end\
5116\
5117 if negativeX < 1 then\
5118 local nodes = self.nodes\
5119 for i = 1, #nodes do\
5120 nodes[ i ].X = nodes[ i ].X - negativeX + 1\
5121 end\
5122\
5123 self.X = self.X + negativeX\
5124 end\
5125\
5126 self.width = totalWidth\
5127 self.height = totalHeight\
5128end\
5129\
5130--[[\
5131 @instance\
5132 @desc A modified Container.shipEvent to avoid shipping events to hidden submenus.\
5133 @param <Event - event>\
5134]]\
5135function ContextMenu:shipEvent( event )\
5136 local nodes = self.nodes\
5137 for i = #nodes, 1, -1 do\
5138 if nodes[ i ].visible then\
5139 nodes[ i ]:handle( event )\
5140 end\
5141 end\
5142end\
5143\
5144--[[\
5145 @instance\
5146 @desc Invokes super (container) handle function. If event is a mouse event and it missed an open subframe the frames will be closed (if it was a CLICK) and the event will be unhandled\
5147 allowing further propagation and usage throughout the application.\
5148 @param <Event - eventObj>\
5149 @return <boolean - propagate>\
5150]]\
5151function ContextMenu:handle( eventObj )\
5152 if not self.super:handle( eventObj ) then return end\
5153\
5154 if eventObj.main == \"MOUSE\" and not self:isMouseColliding( eventObj ) then\
5155 if eventObj.sub == \"CLICK\" then self:closeFrame( 1 ) end\
5156 eventObj.handled = false\
5157 end\
5158\
5159 return true\
5160end\
5161\
5162--[[\
5163 @instance\
5164 @desc Closes the frame using 'frameID', which represents the position of the frame in the 'nodes' table\
5165 @param <number - frameID>\
5166]]\
5167function ContextMenu:closeFrame( frameID )\
5168 local framesToClose, i = { self.nodes[ frameID ] }, 1\
5169 while i <= #framesToClose do\
5170 local subframes = framesToClose[ i ].subframes or {}\
5171 for f = 1, #subframes do\
5172 if subframes[ f ].visible then\
5173 framesToClose[ #framesToClose + 1 ] = subframes[ f ]\
5174 end\
5175 end\
5176\
5177 framesToClose[ i ].visible = false\
5178 i = i + 1\
5179 end\
5180\
5181 self.changed = true\
5182end\
5183\
5184configureConstructor {\
5185 orderedArguments = { \"structure\" },\
5186 requiredArguments = { \"structure\" },\
5187 argumentTypes = {\
5188 structure = \"table\"\
5189 }\
5190}\
5191",
5192["Class.lua"]="--[[\
5193 Titanium Class System - Version 1.1\
5194\
5195 Copyright (c) Harry Felton 2016\
5196]]\
5197\
5198local classes, classRegistry, currentClass, currentRegistry = {}, {}\
5199local reserved = {\
5200 static = true,\
5201 super = true,\
5202 __type = true,\
5203 isCompiled = true,\
5204 compile = true\
5205}\
5206\
5207local missingClassLoader\
5208\
5209local getters = setmetatable( {}, { __index = function( self, name )\
5210 self[ name ] = \"get\" .. name:sub( 1, 1 ):upper() .. name:sub( 2 )\
5211\
5212 return self[ name ]\
5213end })\
5214\
5215local setters = setmetatable( {}, { __index = function( self, name )\
5216 self[ name ] = \"set\"..name:sub(1, 1):upper()..name:sub(2)\
5217\
5218 return self[ name ]\
5219end })\
5220\
5221local isNumber = {}\
5222for i = 0, 15 do isNumber[2 ^ i] = true end\
5223\
5224--[[ Constants ]]--\
5225local ERROR_BUG = \"\\nPlease report this via GitHub @ hbomb79/Titanium\"\
5226local ERROR_GLOBAL = \"Failed to %s to %s\\n\"\
5227local ERROR_NOT_BUILDING = \"No class is currently being built. Declare a class before invoking '%s'\"\
5228\
5229--[[ Helper functions ]]--\
5230local function throw( ... )\
5231 return error( table.concat( { ... }, \"\\n\" ) , 2 )\
5232end\
5233\
5234local function verifyClassEntry( target )\
5235 return type( target ) == \"string\" and type( classes[ target ] ) == \"table\" and type( classRegistry[ target ] ) == \"table\"\
5236end\
5237\
5238local function verifyClassObject( target, autoCompile )\
5239 if not Titanium.isClass( target ) then\
5240 return false\
5241 end\
5242\
5243 if autoCompile and not target:isCompiled() then\
5244 target:compile()\
5245 end\
5246\
5247 return true\
5248end\
5249\
5250local function isBuilding( ... )\
5251 if type( currentRegistry ) == \"table\" or type( currentClass ) == \"table\" then\
5252 if not ( currentRegistry and currentClass ) then\
5253 throw(\"Failed to validate currently building class objects\", \"The 'currentClass' and 'currentRegistry' variables are not both set\\n\", \"currentClass: \"..tostring( currentClass ), \"currentRegistry: \"..tostring( currentRegistry ), ERROR_BUG)\
5254 end\
5255 return true\
5256 end\
5257\
5258 if #({ ... }) > 0 then\
5259 return throw( ... )\
5260 else\
5261 return false\
5262 end\
5263end\
5264\
5265local function getClass( target )\
5266 if verifyClassEntry( target ) then\
5267 return classes[ target ]\
5268 elseif missingClassLoader then\
5269 local oC, oCReg = currentClass, currentRegistry\
5270 currentClass, currentRegistry = nil, nil\
5271\
5272 missingClassLoader( target )\
5273 local c = classes[ target ]\
5274 if not verifyClassObject( c, true ) then\
5275 throw(\"Failed to load missing class '\"..target..\"'.\\n\", \"The missing class loader failed to load class '\"..target..\"'.\\n\")\
5276 end\
5277\
5278 currentClass, currentRegistry = oC, oCReg\
5279\
5280 return c\
5281 else throw(\"Class '\"..target..\"' not found\") end\
5282end\
5283\
5284local function deepCopy( source )\
5285 if type( source ) == \"table\" then\
5286 local copy = {}\
5287 for key, value in next, source, nil do\
5288 copy[ deepCopy( key ) ] = deepCopy( value )\
5289 end\
5290 return copy\
5291 else\
5292 return source\
5293 end\
5294end\
5295\
5296local function propertyCatch( tbl )\
5297 if type( tbl ) == \"table\" then\
5298 if tbl.static then\
5299 if type( tbl.static ) ~= \"table\" then\
5300 throw(\"Invalid entity found in trailing property table\", \"Expected type 'table' for entity 'static'. Found: \"..tostring( tbl.static ), \"\\nThe 'static' entity is for storing static variables, refactor your class declaration.\")\
5301 end\
5302\
5303\
5304 local cStatic, cOwnedStatics = currentRegistry.static, currentRegistry.ownedStatics\
5305 for key, value in pairs( tbl.static ) do\
5306 if reserved[ key ] then\
5307 throw(\
5308 \"Failed to set static key '\"..key..\"' on building class '\"..currentRegistry.type..\"'\",\
5309 \"'\"..key..\"' is reserved by Titanium for internal processes.\"\
5310 )\
5311 end\
5312\
5313 cStatic[ key ] = value\
5314 cOwnedStatics[ key ] = type( value ) == \"nil\" and nil or true\
5315 end\
5316\
5317 tbl.static = nil\
5318 end\
5319\
5320 local cKeys, cOwned = currentRegistry.keys, currentRegistry.ownedKeys\
5321 for key, value in pairs( tbl ) do\
5322 cKeys[ key ] = value\
5323 cOwned[ key ] = type( value ) == \"nil\" and nil or true\
5324 end\
5325 elseif type( tbl ) ~= \"nil\" then\
5326 throw(\"Invalid trailing entity caught\\n\", \"An invalid object was caught trailing the class declaration for '\"..currentRegistry.type..\"'.\\n\", \"Object: '\"..tostring( tbl )..\"' (\"..type( tbl )..\")\"..\"\\n\", \"Expected [tbl | nil]\")\
5327 end\
5328end\
5329\
5330local function createFunctionWrapper( fn, superLevel )\
5331 return function( instance, ... )\
5332 local oldSuper = instance:setSuper( superLevel )\
5333\
5334 local v = { fn( ... ) }\
5335\
5336 instance.super = oldSuper\
5337\
5338 return unpack( v )\
5339 end\
5340end\
5341\
5342\
5343--[[ Local Functions ]]--\
5344local function compileSupers( targets )\
5345 local inheritedKeys, superMatrix = {}, {}, {}\
5346 local function compileSuper( target, id )\
5347 local factories = {}\
5348 local targetType = target.__type\
5349 local targetReg = classRegistry[ targetType ]\
5350\
5351 for key, value in pairs( targetReg.keys ) do\
5352 if not reserved[ key ] then\
5353 local toInsert = value\
5354 if type( value ) == \"function\" then\
5355 factories[ key ] = function( instance, ... )\
5356 --print(\"Super factory for \"..key..\"\\nArgs: \"..( function( args ) local s = \"\"; for i = 1, #args do s = s .. \" - \" .. tostring( args[ i ] ) .. \"\\n\" end return s end )( { ... } ))\
5357 local oldSuper = instance:setSuper( id + 1 )\
5358 local v = { value( instance, ... ) }\
5359\
5360 instance.super = oldSuper\
5361 return unpack( v )\
5362 end\
5363\
5364 toInsert = factories[ key ]\
5365 end\
5366\
5367 inheritedKeys[ key ] = toInsert\
5368 end\
5369 end\
5370\
5371 -- Handle inheritance\
5372 for key, value in pairs( inheritedKeys ) do\
5373 if type( value ) == \"function\" and not factories[ key ] then\
5374 factories[ key ] = value\
5375 end\
5376 end\
5377\
5378 superMatrix[ id ] = { factories, targetReg }\
5379 end\
5380\
5381 for id = #targets, 1, -1 do compileSuper( targets[ id ], id ) end\
5382\
5383 return inheritedKeys, function( instance )\
5384 local matrix, matrixReady = {}\
5385 local function generateMatrix( target, id )\
5386 local superTarget, matrixTbl, matrixMt = superMatrix[ id ], {}, {}\
5387 local factories, reg = superTarget[ 1 ], superTarget[ 2 ]\
5388\
5389 matrixTbl.__type = reg.type\
5390\
5391 local raw, owned, wrapCache, factory, upSuper = reg.raw, reg.ownedKeys, {}\
5392\
5393 function matrixMt:__tostring()\
5394 return \"[\"..reg.type..\"] Super #\"..id..\" of '\"..instance.__type..\"' instance\"\
5395 end\
5396 function matrixMt:__newindex( k, v )\
5397 if not matrixReady and k == \"super\" then\
5398 upSuper = v\
5399 return\
5400 end\
5401\
5402 throw(\"Cannot set keys on super. Illegal action.\")\
5403 end\
5404 function matrixMt:__index( k )\
5405 factory = factories[ k ]\
5406 if factory then\
5407 if not wrapCache[ k ] then\
5408 wrapCache[ k ] = (function( _, ... )\
5409 return factory( instance, ... )\
5410 end)\
5411 end\
5412\
5413 return wrapCache[ k ]\
5414 else\
5415 if k == \"super\" then\
5416 return upSuper\
5417 else\
5418 return throw(\"Cannot lookup value for key '\"..k..\"' on super\", \"Only functions can be accessed from supers.\")\
5419 end\
5420 end\
5421 end\
5422 function matrixMt:__call( instance, ... )\
5423 local init = self.__init__\
5424 if type( init ) == \"function\" then\
5425 return init( self, ... )\
5426 else\
5427 throw(\"Failed to execute super constructor. __init__ method not found\")\
5428 end\
5429 end\
5430\
5431 setmetatable( matrixTbl, matrixMt )\
5432 return matrixTbl\
5433 end\
5434\
5435 local last = matrix\
5436 for id = 1, #targets do\
5437 last.super = generateMatrix( targets[ id ], id )\
5438 last = last.super\
5439 end\
5440\
5441 martixReady = true\
5442 return matrix\
5443 end\
5444end\
5445local function mergeValues( a, b )\
5446 if type( a ) == \"table\" and type( b ) == \"table\" then\
5447 local merged = deepCopy( a ) or throw( \"Invalid base table for merging.\" )\
5448\
5449 if #b == 0 and next( b ) then\
5450 for key, value in pairs( b ) do merged[ key ] = value end\
5451 elseif #b > 0 then\
5452 for i = 1, #b do table.insert( merged, i, b[ i ] ) end\
5453 end\
5454\
5455 return merged\
5456 end\
5457\
5458 return b == nil and a or b\
5459end\
5460local constructorTargets = { \"orderedArguments\", \"requiredArguments\", \"argumentTypes\", \"useProxy\" }\
5461local function compileConstructor( superReg )\
5462 local constructorConfiguration = {}\
5463\
5464 local superConfig, currentConfig = superReg.constructor, currentRegistry.constructor\
5465 if not currentConfig and superConfig then\
5466 currentRegistry.constructor = superConfig\
5467 return\
5468 elseif currentConfig and not superConfig then\
5469 superConfig = {}\
5470 elseif not currentConfig and not superConfig then\
5471 return\
5472 end\
5473\
5474 local constructorKey\
5475 for i = 1, #constructorTargets do\
5476 constructorKey = constructorTargets[ i ]\
5477 if not ( ( constructorKey == \"orderedArguments\" and currentConfig.clearOrdered ) or ( constructorKey == \"requiredArguments\" and currentConfig.clearRequired ) ) then\
5478 currentConfig[ constructorKey ] = mergeValues( superConfig[ constructorKey ], currentConfig[ constructorKey ] )\
5479 end\
5480 end\
5481end\
5482local function compileCurrent()\
5483 isBuilding(\
5484 \"Cannot compile current class.\",\
5485 \"No class is being built at time of call. Declare a class be invoking 'compileCurrent'\"\
5486 )\
5487 local ownedKeys, ownedStatics, allMixins = currentRegistry.ownedKeys, currentRegistry.ownedStatics, currentRegistry.allMixins\
5488\
5489 -- Mixins\
5490 local cConstructor = currentRegistry.constructor\
5491 for target in pairs( currentRegistry.mixins ) do\
5492 allMixins[ target ] = true\
5493 local reg = classRegistry[ target ]\
5494\
5495 local t = { { reg.keys, currentRegistry.keys, ownedKeys }, { reg.static, currentRegistry.static, ownedStatics }, { reg.alias, currentRegistry.alias, currentRegistry.alias } }\
5496 for i = 1, #t do\
5497 local source, target, owned = t[ i ][ 1 ], t[ i ][ 2 ], t[ i ][ 3 ]\
5498 for key, value in pairs( source ) do\
5499 if not owned[ key ] then\
5500 target[ key ] = value\
5501 end\
5502 end\
5503 end\
5504\
5505 local constructor = reg.constructor\
5506 if constructor then\
5507 if constructor.clearOrdered then cConstructor.orderedArguments = nil end\
5508 if constructor.clearRequired then cConstructor.requiredArguments = nil end\
5509\
5510 local target\
5511 for i = 1, #constructorTargets do\
5512 target = constructorTargets[ i ]\
5513 cConstructor[ target ] = mergeValues( cConstructor[ target ], constructor[ target ] )\
5514 end\
5515 end\
5516 end\
5517\
5518 -- Supers\
5519 local superKeys\
5520 if currentRegistry.super then\
5521 local supers = {}\
5522\
5523 local last, c, newC = currentRegistry.super.target\
5524 while last do\
5525 c = getClass( last, true )\
5526\
5527 supers[ #supers + 1 ] = c\
5528 newC = classRegistry[ last ].super\
5529 last = newC and newC.target or false\
5530 end\
5531\
5532 superKeys, currentRegistry.super.matrix = compileSupers( supers )\
5533\
5534 -- Inherit alias from previous super\
5535 local currentAlias = currentRegistry.alias\
5536 for alias, redirect in pairs( classRegistry[ supers[ 1 ].__type ].alias ) do\
5537 if currentAlias[ alias ] == nil then\
5538 currentAlias[ alias ] = redirect\
5539 end\
5540 end\
5541\
5542 for mName in pairs( classRegistry[ supers[ 1 ].__type ].allMixins ) do\
5543 allMixins[ mName ] = true\
5544 end\
5545\
5546 compileConstructor( classRegistry[ supers[ 1 ].__type ] )\
5547 end\
5548\
5549 -- Generate instance function wrappers\
5550 local instanceWrappers, instanceVariables = {}, {}\
5551 for key, value in pairs( currentRegistry.keys ) do\
5552 if type( value ) == \"function\" then\
5553 instanceWrappers[ key ] = true\
5554 instanceVariables[ key ] = createFunctionWrapper( value, 1 )\
5555 else\
5556 instanceVariables[ key ] = value\
5557 end\
5558 end\
5559 if superKeys then\
5560 for key, value in pairs( superKeys ) do\
5561 if not instanceVariables[ key ] then\
5562 if type( value ) == \"function\" then\
5563 instanceWrappers[ key ] = true\
5564 instanceVariables[ key ] = function( _, ... ) return value( ... ) end\
5565 else\
5566 instanceVariables[ key ] = value\
5567 end\
5568 end\
5569 end\
5570 end\
5571\
5572 -- Finish compilation\
5573 currentRegistry.initialWrappers = instanceWrappers\
5574 currentRegistry.initialKeys = instanceVariables\
5575 currentRegistry.compiled = true\
5576\
5577 currentRegistry = nil\
5578 currentClass = nil\
5579\
5580end\
5581local function spawn( target, ... )\
5582 if not verifyClassEntry( target ) then\
5583 throw(\
5584 \"Failed to spawn class instance of '\"..tostring( target )..\"'\",\
5585 \"A class entity named '\"..tostring( target )..\"' doesn't exist.\"\
5586 )\
5587 end\
5588\
5589 local classEntry, classReg = classes[ target ], classRegistry[ target ]\
5590 if classReg.abstract or not classReg.compiled then\
5591 throw(\
5592 \"Failed to instantiate class '\"..classReg.type..\"'\",\
5593 \"Class '\"..classReg.type..\"' \"..(classReg.abstract and \"is abstract. Cannot instantiate abstract class.\" or \"has not been compiled. Cannot instantiate.\")\
5594 )\
5595 end\
5596\
5597 local wrappers, wrapperCache = deepCopy( classReg.initialWrappers ), {}\
5598 local raw = deepCopy( classReg.initialKeys )\
5599 local alias = classReg.alias\
5600\
5601 local instanceID = string.sub( tostring( raw ), 8 )\
5602\
5603 local supers = {}\
5604 local function indexSupers( last, ID )\
5605 while last.super do\
5606 supers[ ID ] = last.super\
5607 last = last.super\
5608 ID = ID + 1\
5609 end\
5610 end\
5611\
5612 local instanceObj, instanceMt = { raw = raw, __type = target, __instance = true, __ID = instanceID }, { __metatable = {} }\
5613 local getting, useGetters, setting, useSetters = {}, true, {}, true\
5614 function instanceMt:__index( k )\
5615 local k = alias[ k ] or k\
5616\
5617 local getFn = getters[ k ]\
5618 if useGetters and not getting[ k ] and wrappers[ getFn ] then\
5619 getting[ k ] = true\
5620 local v = self[ getFn ]( self )\
5621 getting[ k ] = nil\
5622\
5623 return v\
5624 elseif wrappers[ k ] then\
5625 if not wrapperCache[ k ] then\
5626 wrapperCache[ k ] = function( ... )\
5627 --print(\"Wrapper for \"..k..\". Arguments: \"..( function( args ) local s = \"\"; for i = 1, #args do s = s .. \" - \" .. tostring( args[ i ] ) .. \"\\n\" end return s end )( { ... } ) )\
5628 return raw[ k ]( self, ... )\
5629 end\
5630 end\
5631\
5632 return wrapperCache[ k ]\
5633 else return raw[ k ] end\
5634 end\
5635\
5636 function instanceMt:__newindex( k, v )\
5637 local k = alias[ k ] or k\
5638\
5639 local setFn = setters[ k ]\
5640 if useSetters and not setting[ k ] and wrappers[ setFn ] then\
5641 setting[ k ] = true\
5642 self[ setFn ]( self, v )\
5643 setting[ k ] = nil\
5644 elseif type( v ) == \"function\" and useSetters then\
5645 wrappers[ k ] = true\
5646 raw[ k ] = createFunctionWrapper( v, 1 )\
5647 else\
5648 wrappers[ k ] = nil\
5649 raw[ k ] = v\
5650 end\
5651 end\
5652\
5653 function instanceMt:__tostring()\
5654 return \"[Instance] \"..target..\" (\"..instanceID..\")\"\
5655 end\
5656\
5657 if classReg.super then\
5658 instanceObj.super = classReg.super.matrix( instanceObj ).super\
5659 indexSupers( instanceObj, 1 )\
5660 end\
5661\
5662 local old\
5663 function instanceObj:setSuper( target )\
5664 old, instanceObj.super = instanceObj.super, supers[ target ]\
5665 return old\
5666 end\
5667\
5668 local function setSymKey( key, value )\
5669 useSetters = false\
5670 instanceObj[ key ] = value\
5671 useSetters = true\
5672 end\
5673\
5674 local resolved\
5675 local resolvedArguments = {}\
5676 function instanceObj:resolve( ... )\
5677 if resolved then return false end\
5678\
5679 local args, config = { ... }, classReg.constructor\
5680 if not config then\
5681 throw(\"Failed to resolve \"..tostring( instance )..\" constructor arguments. No configuration has been set via 'configureConstructor'.\")\
5682 end\
5683\
5684 local configRequired, configOrdered, configTypes, configProxy = config.requiredArguments, config.orderedArguments, config.argumentTypes or {}, config.useProxy or {}\
5685\
5686 local argumentsRequired = {}\
5687 if configRequired then\
5688 local target = type( configRequired ) == \"table\" and configRequired or configOrdered\
5689\
5690 for i = 1, #target do argumentsRequired[ target[ i ] ] = true end\
5691 end\
5692\
5693 local orderedMatrix = {}\
5694 for i = 1, #configOrdered do orderedMatrix[ configOrdered[ i ] ] = i end\
5695\
5696 local proxyAll, proxyMatrix = type( configProxy ) == \"boolean\" and configProxy, {}\
5697 if not proxyAll then\
5698 for i = 1, #configProxy do proxyMatrix[ configProxy[ i ] ] = true end\
5699 end\
5700\
5701 local function handleArgument( position, name, value )\
5702 local desiredType = configTypes[ name ]\
5703 if desiredType == \"colour\" or desiredType == \"color\" then\
5704 --TODO: Check if number is valid (maybe?)\
5705 desiredType = \"number\"\
5706 end\
5707\
5708 if desiredType and type( value ) ~= desiredType then\
5709 return throw(\"Failed to resolve '\"..tostring( target )..\"' constructor arguments. Invalid type for argument '\"..name..\"'. Type \"..configTypes[ name ]..\" expected, \"..type( value )..\" was received.\")\
5710 end\
5711\
5712 resolvedArguments[ name ], argumentsRequired[ name ] = true, nil\
5713 if proxyAll or proxyMatrix[ name ] then\
5714 self[ name ] = value\
5715 else\
5716 setSymKey( name, value )\
5717 end\
5718 end\
5719\
5720 for iter, value in pairs( args ) do\
5721 if configOrdered[ iter ] then\
5722 handleArgument( iter, configOrdered[ iter ], value )\
5723 elseif type( value ) == \"table\" then\
5724 for key, v in pairs( value ) do\
5725 handleArgument( orderedMatrix[ key ], key, v )\
5726 end\
5727 else\
5728 return throw(\"Failed to resolve '\"..tostring( target )..\"' constructor arguments. Invalid argument found at ordered position \"..iter..\".\")\
5729 end\
5730 end\
5731\
5732 if next( argumentsRequired ) then\
5733 local str, name = \"\"\
5734 local function append( cnt )\
5735 str = str ..\"- \"..cnt..\"\\n\"\
5736 end\
5737\
5738 return throw(\"Failed to resolve '\"..tostring( target )..\"' constructor arguments. The following required arguments were not provided:\\n\\n\"..(function()\
5739 str = \"Ordered:\\n\"\
5740 for i = 1, #configOrdered do\
5741 name = configOrdered[ i ]\
5742 if argumentsRequired[ name ] then\
5743 append( name .. \" [#\"..i..\"]\" )\
5744 argumentsRequired[ name ] = nil\
5745 end\
5746 end\
5747\
5748 if next( argumentsRequired ) then\
5749 str = str .. \"\\nTrailing:\\n\"\
5750 for name, _ in pairs( argumentsRequired ) do append( name ) end\
5751 end\
5752\
5753 return str\
5754 end)())\
5755 end\
5756\
5757 resolved = true\
5758 return true\
5759 end\
5760 instanceObj.__resolved = resolvedArguments\
5761\
5762 function instanceObj:can( method )\
5763 return wrappers[ method ] or false\
5764 end\
5765\
5766 local locked = { __index = true, __newindex = true }\
5767 function instanceObj:setMetaMethod( method, fn )\
5768 if type( method ) ~= \"string\" then\
5769 throw( \"Failed to set metamethod '\"..tostring( method )..\"'\", \"Expected string for argument #1, got '\"..tostring( method )..\"' of type \"..type( method ) )\
5770 elseif type( fn ) ~= \"function\" then\
5771 throw( \"Failed to set metamethod '\"..tostring( method )..\"'\", \"Expected function for argument #2, got '\"..tostring( fn )..\"' of type \"..type( fn ) )\
5772 end\
5773\
5774 method = \"__\"..method\
5775 if locked[ method ] then\
5776 throw( \"Failed to set metamethod '\"..tostring( method )..\"'\", \"Metamethod locked\" )\
5777 end\
5778\
5779 instanceMt[ method ] = fn\
5780 end\
5781\
5782 function instanceObj:lockMetaMethod( method )\
5783 if type( method ) ~= \"string\" then\
5784 throw( \"Failed to lock metamethod '\"..tostring( method )..\"'\", \"Expected string, got '\"..tostring( method )..\"' of type \"..type( method ) )\
5785 end\
5786\
5787 locked[ \"__\"..method ] = true\
5788 end\
5789\
5790 setmetatable( instanceObj, instanceMt )\
5791 if type( instanceObj.__init__ ) == \"function\" then instanceObj:__init__( ... ) end\
5792\
5793 for mName in pairs( classReg.allMixins ) do\
5794 if type( instanceObj[ mName ] ) == \"function\" then instanceObj[ mName ]( instanceObj ) end\
5795 end\
5796\
5797 if type( instanceObj.__postInit__ ) == \"function\" then instanceObj:__postInit__( ... ) end\
5798\
5799 return instanceObj\
5800end\
5801\
5802\
5803--[[ Global functions ]]--\
5804\
5805function class( name )\
5806 if isBuilding() then\
5807 throw(\
5808 \"Failed to declare class '\"..tostring( name )..\"'\",\
5809 \"A new class cannot be declared until the currently building class has been compiled.\",\
5810 \"\\nCompile '\"..tostring( currentRegistry.type )..\"' before declaring '\"..tostring( name )..\"'\"\
5811 )\
5812 end\
5813\
5814 local function nameErr( reason )\
5815 throw( \"Failed to declare class '\"..tostring( name )..\"'\\n\", string.format( \"Class name %s is not valid. %s\", tostring( name ), reason ) )\
5816 end\
5817\
5818 if type( name ) ~= \"string\" then\
5819 nameErr \"Class names must be a string\"\
5820 elseif not name:find \"%a\" then\
5821 nameErr \"No alphabetic characters could be found\"\
5822 elseif name:find \"%d\" then\
5823 nameErr \"Class names cannot contain digits\"\
5824 elseif classes[ name ] then\
5825 nameErr \"A class with that name already exists\"\
5826 elseif reserved[ name ] then\
5827 nameErr (\"'\"..name..\"' is reserved for Titanium processes\")\
5828 else\
5829 local char = name:sub( 1, 1 )\
5830 if char ~= char:upper() then\
5831 nameErr \"Class names must begin with an uppercase character\"\
5832 end\
5833 end\
5834\
5835 local classReg = {\
5836 type = name,\
5837\
5838 static = {},\
5839 keys = {},\
5840 ownedStatics = {},\
5841 ownedKeys = {},\
5842\
5843 initialWrappers = {},\
5844 initialKeys = {},\
5845\
5846 mixins = {},\
5847 allMixins = {},\
5848 alias = {},\
5849\
5850 constructor = false,\
5851 super = false,\
5852\
5853 compiled = false,\
5854 abstract = false\
5855 }\
5856\
5857 -- Class metatable\
5858 local classMt = { __metatable = {} }\
5859 function classMt:__tostring()\
5860 return (classReg.compiled and \"[Compiled] \" or \"\") .. \"Class '\"..name..\"'\"\
5861 end\
5862\
5863 local keys, owned = classReg.keys, classReg.ownedKeys\
5864 local staticKeys, staticOwned = classReg.static, classReg.ownedStatics\
5865 function classMt:__newindex( k, v )\
5866 if classReg.compiled then\
5867 throw(\
5868 \"Failed to set key on class base.\", \"\",\
5869 \"This class base is compiled, once a class base is compiled new keys cannot be added to it\",\
5870 \"\\nPerhaps you meant to set the static key '\"..name..\".static.\"..k..\"' instead.\"\
5871 )\
5872 end\
5873\
5874 keys[ k ] = v\
5875 owned[ k ] = type( v ) == \"nil\" and nil or true\
5876 end\
5877 function classMt:__index( k )\
5878 if owned[ k ] then\
5879 throw (\
5880 \"Access to key '\"..k..\"' denied.\",\
5881 \"Instance keys cannot be accessed from a class base, regardless of compiled state\",\
5882 classReg.ownedStatics[ k ] and \"\\nPerhaps you meant to access the static variable '\" .. name .. \".static.\".. k .. \"' instead\" or nil\
5883 )\
5884 elseif staticOwned[ k ] then\
5885 return staticKeys[ k ]\
5886 end\
5887 end\
5888 function classMt:__call( ... )\
5889 return spawn( name, ... )\
5890 end\
5891\
5892 -- Static metatable\
5893 local staticMt = { __index = staticKeys }\
5894 function staticMt:__newindex( k, v )\
5895 staticKeys[ k ] = v\
5896 staticOwned[ k ] = type( v ) == \"nil\" and nil or true\
5897 end\
5898\
5899 -- Class object\
5900 local classObj = { __type = name }\
5901 classObj.static = setmetatable( {}, staticMt )\
5902 classObj.compile = compileCurrent\
5903\
5904 function classObj:isCompiled() return classReg.compiled end\
5905\
5906 function classObj:getRegistry() return classReg end\
5907\
5908 setmetatable( classObj, classMt )\
5909\
5910 -- Export\
5911 currentRegistry = classReg\
5912 classRegistry[ name ] = classReg\
5913\
5914 currentClass = classObj\
5915 classes[ name ] = classObj\
5916\
5917 _G[ name ] = classObj\
5918\
5919 return propertyCatch\
5920end\
5921\
5922function extends( name )\
5923 isBuilding(\
5924 string.format( ERROR_GLOBAL, \"extend\", \"target class '\"..tostring( name )..\"'\" ), \"\",\
5925 string.format( ERROR_NOT_BUILDING, \"extends\" )\
5926 )\
5927\
5928 currentRegistry.super = {\
5929 target = name\
5930 }\
5931 return propertyCatch\
5932end\
5933\
5934function mixin( name )\
5935 if type( name ) ~= \"string\" then\
5936 throw(\"Invalid mixin target '\"..tostring( name )..\"'\")\
5937 end\
5938\
5939 isBuilding(\
5940 string.format( ERROR_GLOBAL, \"mixin\", \"target class '\".. name ..\"'\" ),\
5941 string.format( ERROR_NOT_BUILDING, \"mixin\" )\
5942 )\
5943\
5944 local mixins = currentRegistry.mixins\
5945 if mixins[ name ] then\
5946 throw(\
5947 string.format( ERROR_GLOBAL, \"mixin class '\".. name ..\"'\", \"class '\"..currentRegistry.type)\
5948 \"'\".. name ..\"' has already been mixed in to this target class.\"\
5949 )\
5950 end\
5951\
5952 if not getClass( name, true ) then\
5953 throw(\
5954 string.format( ERROR_GLOBAL, \"mixin class '\".. name ..\"'\", \"class '\"..currentRegistry.type ),\
5955 \"The mixin class '\".. name ..\"' failed to load\"\
5956 )\
5957 end\
5958\
5959 mixins[ name ] = true\
5960 return propertyCatch\
5961end\
5962\
5963function abstract()\
5964 isBuilding(\
5965 \"Failed to enforce abstract class policy\\n\",\
5966 string.format( ERROR_NOT_BUILDING, \"abstract\" )\
5967 )\
5968\
5969 currentRegistry.abstract = true\
5970 return propertyCatch\
5971end\
5972\
5973function alias( target )\
5974 local FAIL_MSG = \"Failed to implement alias targets\\n\"\
5975 isBuilding( FAIL_MSG, string.format( ERROR_NOT_BUILDING, \"alias\" ) )\
5976\
5977 local tbl = type( target ) == \"table\" and target or (\
5978 type( target ) == \"string\" and (\
5979 type( _G[ target ] ) == \"table\" and _G[ target ] or throw( FAIL_MSG, \"Failed to find '\"..tostring( target )..\"' table in global environment.\" )\
5980 ) or throw( FAIL_MSG, \"Expected type table as target, got '\"..tostring( target )..\"' of type \"..type( target ) )\
5981 )\
5982\
5983 local cAlias = currentRegistry.alias\
5984 for alias, redirect in pairs( tbl ) do\
5985 cAlias[ alias ] = redirect\
5986 end\
5987\
5988 return propertyCatch\
5989end\
5990\
5991function configureConstructor( config, clearOrdered, clearRequired )\
5992 isBuilding(\
5993 \"Failed to configure class constructor\\n\",\
5994 string.format( ERROR_NOT_BUILDING, \"configureConstructor\" )\
5995 )\
5996\
5997 if type( config ) ~= \"table\" then\
5998 throw (\
5999 \"Failed to configure class constructor\\n\",\
6000 \"Expected type 'table' as first argument\"\
6001 )\
6002 end\
6003\
6004 local constructor = {\
6005 clearOrdered = clearOrdered or nil,\
6006 clearRequired = clearRequired or nil\
6007 }\
6008 for key, value in pairs( config ) do constructor[ key ] = value end\
6009\
6010 currentRegistry.constructor = constructor\
6011 return propertyCatch\
6012end\
6013\
6014--[[ Class Library ]]--\
6015Titanium = {}\
6016\
6017function Titanium.getGetterName( property ) return getters[ property ] end\
6018\
6019function Titanium.getSetterName( property ) return setters[ property ] end\
6020\
6021function Titanium.getClass( name )\
6022 return classes[ name ]\
6023end\
6024\
6025function Titanium.getClasses()\
6026 return classes\
6027end\
6028\
6029function Titanium.isClass( target )\
6030 return type( target ) == \"table\" and type( target.__type ) == \"string\" and verifyClassEntry( target.__type )\
6031end\
6032\
6033function Titanium.isInstance( target )\
6034 return Titanium.isClass( target ) and target.__instance\
6035end\
6036\
6037function Titanium.typeOf( target, classType, instance )\
6038 if not Titanium.isClass( target ) or ( instance and not Titanium.isInstance( target ) ) then\
6039 return false\
6040 end\
6041\
6042 local targetReg = classRegistry[ target.__type ]\
6043\
6044 return targetReg.type == classType or ( targetReg.super and Titanium.typeOf( classes[ targetReg.super.target ], classType ) ) or false\
6045end\
6046\
6047function Titanium.mixesIn( target, mixinName )\
6048 if not Titanium.isClass( target ) then return false end\
6049\
6050 return classRegistry[ target.__type ].allMixins[ mixinName ]\
6051end\
6052\
6053function Titanium.setClassLoader( fn )\
6054 if type( fn ) ~= \"function\" then\
6055 throw( \"Failed to set class loader\", \"Value '\"..tostring( fn )..\"' is invalid, expected function\" )\
6056 end\
6057\
6058 missingClassLoader = fn\
6059end\
6060\
6061local preprocessTargets = {\"class\", \"extends\", \"alias\", \"mixin\"}\
6062function Titanium.preprocess( text )\
6063 local keyword\
6064 for i = 1, #preprocessTargets do\
6065 keyword = preprocessTargets[ i ]\
6066\
6067 for value in text:gmatch( keyword .. \" ([_%a][_%w]*)%s\" ) do\
6068 text = text:gsub( keyword .. \" \" .. value, keyword..\" \\\"\"..value..\"\\\"\" )\
6069 end\
6070 end\
6071\
6072 for name in text:gmatch( \"abstract class (\\\".[^%s]+\\\")\" ) do\
6073 text = text:gsub( \"abstract class \"..name, \"class \"..name..\" abstract()\" )\
6074 end\
6075\
6076 return text\
6077end\
6078",
6079["Checkbox.ti"]="--[[\
6080 The checkbox is a node that can be toggled on and off\
6081]]\
6082\
6083class \"Checkbox\" extends \"Node\" mixin \"MActivatable\" mixin \"MTogglable\" {\
6084 checkedMark = \"x\";\
6085 uncheckedMark = \" \";\
6086\
6087 allowMouse = true;\
6088}\
6089\
6090--[[\
6091 @constructor\
6092 @desc Resolves arguments and calls super constructor\
6093 @param <number - X>, <number - Y>\
6094]]\
6095function Checkbox:__init__( ... )\
6096 self:resolve( ... )\
6097 self:super()\
6098\
6099 self:register(\"checkedMark\", \"uncheckedMark\")\
6100end\
6101\
6102--[[\
6103 @instance\
6104 @desc Sets the checkbox to 'active' when clicked\
6105 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
6106]]\
6107function Checkbox:onMouseClick( event, handled, within )\
6108 if not handled then\
6109 self.active = within\
6110\
6111 if within then\
6112 event.handled = true\
6113 end\
6114 end\
6115end\
6116\
6117--[[\
6118 @instance\
6119 @desc Sets the checkbox to inactive when the mouse button is released. If released on checkbox while active 'onToggle' callback is fired and the checkbox is toggled.\
6120 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
6121]]\
6122function Checkbox:onMouseUp( event, handled, within )\
6123 if not handled and within and self.active then\
6124 self:toggle( event, handled, within )\
6125\
6126 event.handled = true\
6127 end\
6128\
6129 self.active = false\
6130end\
6131\
6132--[[\
6133 @instance\
6134 @desc If a label which specifies this node as its 'labelFor' paramater is clicked this function will be called, causing the checkbox to toggle\
6135 @param <LabelInstance - label>, <MouseEvent - event>, <boolean - handled>, <boolean - within>\
6136]]\
6137function Checkbox:onLabelClicked( label, event, handled, within )\
6138 self:toggle( event, handled, within, label )\
6139 event.handled = true\
6140end\
6141\
6142--[[\
6143 @instance\
6144 @desc Draws the checkbox to the canvas\
6145 @param [boolean - force]\
6146]]\
6147function Checkbox:draw( force )\
6148 local raw = self.raw\
6149 if raw.changed or force then\
6150 local toggled, tc, bg = self.toggled\
6151 if not self.enabled then\
6152 tc, bg = raw.disabledColour, raw.disabledBackgroundColour\
6153 elseif toggled then\
6154 tc, bg = raw.toggledColour, raw.toggledBackgroundColour\
6155 elseif self.active then\
6156 tc, bg = raw.activeColour, raw.activeBackgroundColour\
6157 end\
6158\
6159 raw.canvas:drawPoint( 1, 1, toggled and raw.checkedMark or raw.uncheckedMark, tc, bg )\
6160 raw.changed = false\
6161 end\
6162end\
6163\
6164configureConstructor( {\
6165 orderedArguments = { \"X\", \"Y\" },\
6166 argumentTypes = {\
6167 checkedMark = \"string\",\
6168 uncheckedMark = \"string\"\
6169 }\
6170}, true, true )\
6171",
6172["Parser.ti"]="--[[\
6173 The parser class \"should\" be extended by classes that are used to parser lexer token output.\
6174]]\
6175\
6176class \"Parser\" abstract() {\
6177 position = 0;\
6178 tokens = {};\
6179}\
6180\
6181--[[\
6182 @constructor\
6183 @desc Sets the tokens of the parser to those passed and begins parsing\
6184 @param <table - tokens>\
6185]]\
6186function Parser:__init__( tokens )\
6187 if type( tokens ) ~= \"table\" then\
6188 return error \"Failed to parse. Invalid tokens\"\
6189 end\
6190\
6191 self.tokens = tokens\
6192 self:parse()\
6193end\
6194\
6195--[[\
6196 @instance\
6197 @desc Returns the token at 'position'\
6198]]\
6199function Parser:getCurrentToken()\
6200 return self.tokens[ self.position ]\
6201end\
6202\
6203--[[\
6204 @instance\
6205 @desc Returns the token 'amount' ahead of the current position. Defaults to one position ahead\
6206]]\
6207function Parser:peek( amount )\
6208 return self.tokens[ self.position + ( amount or 1 ) ]\
6209end\
6210\
6211--[[\
6212 @instance\
6213 @desc Tests the adjacent tokens to see if they are the correct type. Offsets can be provided and missing tokens can be configured to cause test failure\
6214 @param [string - before], [string - after], [boolean - optional], [number - beforeOffset], [number - afterOffset], [boolean - disallowMissing]\
6215\
6216 Note: If a token doesn't exist, it will NOT cause the test to fail unless 'disallowMissing' is set to true.\
6217]]\
6218function Parser:testAdjacent( before, after, optional, beforeOffset, afterOffset, disallowMissing )\
6219 local leading, leadingPass, trailing, trailingPass = false, not before, false, not after\
6220 local function test( token, filter )\
6221 if not token then return not disallowMissing end\
6222\
6223 if type( filter ) == \"table\" then\
6224 for i = 1, #filter do\
6225 if token.type == filter[ i ] then return true end\
6226 end\
6227 else return token.type == filter end\
6228 end\
6229\
6230 if before then\
6231 leading = self:peek( -1 - ( beforeOffset or 0 ) )\
6232 leadingPass = test( leading, before )\
6233 end\
6234\
6235\
6236 if after then\
6237 trailing = self:peek( 1 + ( afterOffset or 0 ) )\
6238 trailingPass = test( trailing, after )\
6239 end\
6240\
6241 return ( optional and ( trailingPass or leadingPass ) or ( not optional and trailingPass and leadingPass ) ), leading, trailing\
6242end\
6243\
6244--[[\
6245 @instance\
6246 @desc Advances 'position' by one and returns the token at the new position\
6247]]\
6248function Parser:stepForward( amount )\
6249 self.position = self.position + ( amount or 1 )\
6250 return self:getCurrentToken()\
6251end\
6252\
6253--[[\
6254 @instance\
6255 @desc Throws a error prefixed with information about the token being parsed at the time of error.\
6256]]\
6257function Parser:throw( e, token )\
6258 local token = token or self:getCurrentToken()\
6259 if not token then\
6260 return error( \"Parser (\"..tostring( self.__type )..\") Error: \"..e, 2 )\
6261 end\
6262\
6263 return error( \"Parser (\"..tostring( self.__type )..\") Error. Line \"..token.line..\", char \"..token.char .. \": \"..e, 2 )\
6264end\
6265",
6266["Button.ti"]="--[[\
6267 A Button is a node that can be clicked to trigger a callback.\
6268 The button can containtext which can span multiple lines, however if too much text is entered it will be truncated to fit the button dimensions.\
6269\
6270 If buttonLock is 1 or 2, the mouse button used to click the button must match the value. Eg: If self.buttonLock == 1, the mouse button must be 1 when clicked to effect the button.\
6271 If the buttonLock value is 0, any button value will be accepted\
6272]]\
6273\
6274class \"Button\" extends \"Node\" mixin \"MTextDisplay\" mixin \"MActivatable\" {\
6275 allowMouse = true;\
6276 buttonLock = 1;\
6277}\
6278\
6279--[[\
6280 @constructor\
6281 @desc Accepts button arguments and resolves them.\
6282 @param <string - text>, [number - X], [number - Y], [number - width], [number - height]\
6283]]\
6284function Button:__init__( ... )\
6285 self:resolve( ... )\
6286 self:super()\
6287\
6288 self:register(\"width\", \"height\", \"buttonLock\")\
6289end\
6290\
6291--[[\
6292 @instance\
6293 @desc Sets the button to 'active' when the button is clicked with the valid mouse button (self.buttonLock)\
6294 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
6295]]\
6296function Button:onMouseClick( event, handled, within )\
6297 if not handled and within and ( self.buttonLock == 0 or event.button == self.buttonLock ) then\
6298 self.active, event.handled = true, true\
6299 end\
6300end\
6301\
6302--[[\
6303 @instance\
6304 @desc Sets the button to inactive when the mouse button is released. If released on button while active 'onTrigger' callback is fired.\
6305 @param <MouseEvent - event>, <boolean - handled>, <boolean - within>\
6306]]\
6307function Button:onMouseUp( event, handled, within )\
6308 if within and not handled and self.active then\
6309 event.handled = true\
6310 self:executeCallbacks \"trigger\"\
6311 end\
6312\
6313 self.active = false\
6314end\
6315\
6316--[[\
6317 @instance\
6318 @desc Draws the text to the node canvas\
6319 @param [boolean - force]\
6320]]\
6321function Button:draw( force )\
6322 local raw = self.raw\
6323 if raw.changed or force then\
6324 local tc, bg\
6325 if not self.enabled then\
6326 bg, tc = raw.disabledBackgroundColour, raw.disabledColour\
6327 elseif self.active then\
6328 bg, tc = raw.activeBackgroundColour, raw.activeColour\
6329 end\
6330\
6331 raw.canvas:clear( bg )\
6332 self:drawText( bg, tc )\
6333\
6334 raw.changed = false\
6335 end\
6336end\
6337\
6338--[[\
6339 @instance\
6340 @desc Sets the text of the button and then wraps the new text for display.\
6341 @param <string - text>\
6342]]\
6343function Button:setText( text )\
6344 if self.text == text then return end\
6345\
6346 self.text = text\
6347 self.changed = true\
6348 self:wrapText()\
6349end\
6350\
6351--[[\
6352 @instance\
6353 @desc Sets the width of the button and then re-wraps the text to fit in the dimensions.\
6354 @param <number - width>\
6355]]\
6356function Button:setWidth( width )\
6357 self.super:setWidth( width )\
6358 self:wrapText()\
6359end\
6360\
6361configureConstructor {\
6362 orderedArguments = { \"text\" },\
6363 requiredArguments = { \"text\" },\
6364 argumentTypes = {\
6365 buttonLock = \"number\"\
6366 }\
6367}\
6368",
6369["RedirectCanvas.ti"]="--[[\
6370 The RedirectCanvas is a class \"to\" be used by nodes that wish to redirect the term object. This canvas provides a terminal redirect and keeps track\
6371 of the terminals properties set inside the wrapped program (via the term methods).\
6372\
6373 This allows emulation of a shell program inside of Titanium without causing visual issues due to the shell program drawing directly to the terminal and not\
6374 through Titaniums canvas system.\
6375--]]\
6376\
6377local stringLen, stringSub = string.len, string.sub\
6378local isColour = term.isColour()\
6379\
6380local function testColour( col )\
6381 if not isColour and ( col ~= 1 or col ~= 32768 or col ~= 256 or col ~= 128 ) then\
6382 error \"Colour not supported\"\
6383 end\
6384\
6385 return true\
6386end\
6387\
6388class \"RedirectCanvas\" extends \"NodeCanvas\"\
6389\
6390function RedirectCanvas:__init__( ... )\
6391 self:resetTerm()\
6392 self:super( ... )\
6393end\
6394\
6395function RedirectCanvas:resetTerm()\
6396 self.tX, self.tY, self.tColour, self.tBackgroundColour, self.tCursor = 1, 1, 1, 32768, false;\
6397 self:clear( 32768, true )\
6398end\
6399\
6400--[[\
6401 @instance\
6402 @desc Returns a table compatible with `term.redirect`\
6403 @return <table - redirect>\
6404]]\
6405function RedirectCanvas:getTerminalRedirect()\
6406 local redirect = {}\
6407\
6408 function redirect.write( text )\
6409 text = tostring( text )\
6410 local tc, bg, tX, tY = self.tColour, self.tBackgroundColour, self.tX, self.tY\
6411 local buffer, position = self.buffer, self.width * ( tY - 1 ) + tX\
6412\
6413 for i = 1, math.min( stringLen( text ), self.width - tX + 1 ) do\
6414 buffer[ position ] = { stringSub( text, i, i ), tc, bg }\
6415 position = position + 1\
6416 end\
6417\
6418 self.tX = tX + stringLen( text )\
6419 end\
6420\
6421 function redirect.blit( text, colour, background )\
6422 if stringLen( text ) ~= stringLen( colour ) or stringLen( text ) ~= stringLen( background ) then\
6423 return error \"blit arguments must be the same length\"\
6424 end\
6425\
6426 local tX, hex = self.tX, TermCanvas.static.hex\
6427 local buffer, position = self.buffer, self.width * ( self.tY - 1 ) + tX\
6428\
6429 for i = 1, math.min( stringLen( text ), self.width - tX + 1 ) do\
6430 buffer[ position ] = { stringSub( text, i, i ), hex[ stringSub( colour, i, i ) ], hex[ stringSub( background, i, i ) ] }\
6431 position = position + 1\
6432 end\
6433\
6434 self.tX = tX + stringLen( text )\
6435 end\
6436\
6437 function redirect.clear()\
6438 self:clear( self.tBackgroundColour, true )\
6439 end\
6440\
6441 function redirect.clearLine()\
6442 local px = { \" \", self.tColour, self.tBackgroundColour }\
6443 local buffer, position = self.buffer, self.width * ( self.tY - 1 )\
6444\
6445 for i = 1, self.width do\
6446 buffer[ position ] = px\
6447 position = position + 1\
6448 end\
6449 end\
6450\
6451 function redirect.getCursorPos()\
6452 return self.tX, self.tY\
6453 end\
6454\
6455 function redirect.setCursorPos( x, y )\
6456 self.tX, self.tY = math.floor( x ), math.floor( y )\
6457 end\
6458\
6459 function redirect.getSize()\
6460 return self.width, self.height\
6461 end\
6462\
6463 function redirect.setCursorBlink( blink )\
6464 self.tCursor = blink\
6465 end\
6466\
6467 function redirect.setTextColour( tc )\
6468 if testColour( tc ) then\
6469 self.tColour = tc\
6470 end\
6471 end\
6472\
6473 function redirect.getTextColour()\
6474 return self.tColour\
6475 end\
6476\
6477 function redirect.setBackgroundColour( bg )\
6478 if testColour( bg ) then\
6479 self.tBackgroundColour = bg\
6480 end\
6481 end\
6482\
6483 function redirect.getBackgroundColour()\
6484 return self.tBackgroundColour\
6485 end\
6486\
6487 function redirect.scroll( n )\
6488 local offset, buffer, nL = self.width * n, self.buffer, n < 0\
6489 local pixelCount, blank = self.width * self.height, { \" \", self.tColour, self.tBackgroundColour }\
6490\
6491 for i = nL and pixelCount or 1, nL and 1 or pixelCount, nL and -1 or 1 do\
6492 buffer[ i ] = buffer[ i + offset ] or blank\
6493 end\
6494 end\
6495\
6496 function redirect.isColour()\
6497 return isColour\
6498 end\
6499\
6500 -- American spelling compatibility layer\
6501 redirect.isColor = redirect.isColour\
6502\9redirect.setBackgroundColor = redirect.setBackgroundColour\
6503\9redirect.setTextColor = redirect.setTextColour\
6504\9redirect.getBackgroundColor = redirect.getBackgroundColour\
6505\9redirect.getTextColor = redirect.getTextColour\
6506\
6507 return redirect\
6508end\
6509\
6510--[[\
6511 @instance\
6512 @desc Modified Canvas.clear. Only sets pixels that do not exist (doesn't really clear the canvas, just ensures it is the correct size).\
6513 This is to prevent the program running via the term redirect isn't cleared away. Call this function with 'force' and all pixels will be\
6514 replaced (the terminal redirect uses this method).\
6515\
6516 Alternatively, self.getTerminalRedirect.clear() will also clear the canvas entirely\
6517 @param [number - col], [boolean - force]\
6518]]\
6519function RedirectCanvas:clear( col, force )\
6520 local col = col or self.tBackgroundColour\
6521 local pixel, buffer = { \" \", col, col }, self.buffer\
6522\
6523 for index = 1, self.width * self.height do\
6524 if not buffer[ index ] or force then\
6525 buffer[ index ] = pixel\
6526 end\
6527 end\
6528end\
6529",
6530["MouseEvent.ti"]="local string_sub, string_upper = string.sub, string.upper\
6531\
6532class \"MouseEvent\" extends \"Event\" {\
6533 inBounds = false;\
6534 main = \"MOUSE\";\
6535\
6536 isWithin = true;\
6537}\
6538\
6539--[[\
6540 @constructor\
6541 @desc Sets the values given in their respective instance keys. Stores all values into a table 'data'.\
6542 @param <string - name>, <number - button>, <number - X>, <number - Y>, [string - sub]\
6543]]\
6544function MouseEvent:__init__( name, button, X, Y, sub )\
6545 self.name = name\
6546 self.button = button\
6547 self.X = X\
6548 self.Y = Y\
6549\
6550 self.sub = sub or string_upper( string_sub( name, 7 ) )\
6551\
6552 self.data = { name, button, X, Y }\
6553end\
6554\
6555--[[\
6556 @instance\
6557 @desc Returns true if the mouse event was inside of the bounds provided.\
6558 @param <number - x>, <number - y>, <number - w>, <number - h>\
6559 @return <boolean - inBounds>\
6560]]\
6561function MouseEvent:within( x, y, w, h )\
6562 local X, Y = self.X, self.Y\
6563\
6564 return X >= x and Y >= y and X <= -1 + x + w and Y <= -1 + y + h\
6565end\
6566\
6567--[[\
6568 @instance\
6569 @desc Returns true if the mouse event was inside the bounds of the parent provided (x, y, width and height)\
6570 @param <NodeContainer - parent>\
6571]]\
6572function MouseEvent:withinParent( parent )\
6573 return self:within( parent.X, parent.Y, parent.width, parent.height )\
6574end\
6575\
6576--[[\
6577 @instance\
6578 @desc Clones 'self' and adjusts it's X & Y positions so that they're relative to 'parent'.\
6579 @param <NodeContainer - parent>\
6580 @return <MouseEvent Instance - clone>\
6581\
6582 Note: The clone's 'handle' method has been adjusted to also call 'handle' on the master event obj (self).\
6583]]\
6584function MouseEvent:clone( parent )\
6585 local clone = MouseEvent( self.name, self.button, self.X - parent.X + 1, self.Y - parent.Y + 1, self.sub )\
6586\
6587 clone.handled = self.handled\
6588 clone.isWithin = self.isWithin\
6589 clone.setHandled = function( clone, handled )\
6590 clone.handled = handled\
6591 self.handled = handled --TODO: Make sure 'self' refers to the object which 'clone' was invoked on, not the clone.\
6592 end\
6593\
6594 return clone\
6595end\
6596",
6597["Tween.ti"]="class \"Tween\" {\
6598 static = {\
6599 easing = {}\
6600 };\
6601\
6602 object = false;\
6603\
6604 property = false;\
6605 initial = false;\
6606 final = false;\
6607\
6608 duration = 0;\
6609 clock = 0;\
6610}\
6611\
6612--[[\
6613 @constructor\
6614 @desc Constructs the tween instance, converting the 'easing' property into a function (if it's a string) and also stores the initial value of the property for later use.\
6615 @param <Object - object>, <string - name>, <string - property>, <number - final>, <number - duration>, [string/function - easing]\
6616]]\
6617function Tween:__init__( ... )\
6618 self:resolve( ... )\
6619 if not Titanium.isInstance( self.object ) then\
6620 return error(\"Argument 'object' for tween must be a Titanium instance. '\"..tostring( self.object )..\"' is not a Titanium instance.\")\
6621 end\
6622\
6623 local easing = self.easing or \"linear\"\
6624 if type( easing ) == \"string\" then\
6625 self.easing = Tween.static.easing[ easing ] or error(\"Easing type '\"..tostring( easing )..\"' could not be found in 'Tween.static.easing'.\")\
6626 elseif type( easing ) == \"function\" then\
6627 self.easing = easing\
6628 else\
6629 return error \"Tween easing invalid. Must be a function to be invoked or name of easing type\"\
6630 end\
6631\
6632 self.initial = self.object[ self.property ]\
6633 self.clock = 0\
6634end\
6635\
6636--[[\
6637 @instance\
6638 @desc Sets the 'property' of 'object' to the rounded (down) result of the easing function selected. Passes the current clock time, the initial value, the difference between the initial and final values and the total Tween duration.\
6639]]\
6640function Tween:performEasing()\
6641 self.object[ self.property ] = math.floor( self.easing( self.clock, self.initial, self.final - self.initial, self.duration ) + .5 )\
6642end\
6643\
6644--[[\
6645 @instance\
6646 @desc Updates the tween by increasing 'clock' by 'dt' via the setter 'setClock'\
6647 @param <number - dt>\
6648 @return <boolean - finished>\
6649]]\
6650function Tween:update( dt )\
6651 return self:setClock( self.clock + dt )\
6652end\
6653\
6654--[[\
6655 @instance\
6656 @desc Sets the clock time to zero\
6657 @param <boolean - finished>\
6658]]\
6659function Tween:reset()\
6660 return self:setClock( 0 )\
6661end\
6662\
6663--[[\
6664 @instance\
6665 @desc Sets the current 'clock'. If the clock is a boundary number, it is adjusted to match the boundary - otherwise it is set as is. Once set, 'performEasing' is called and the state of the Tween (finished or not) is returned\
6666 @param <number - clock>\
6667 @return <boolean - finished>\
6668]]\
6669function Tween:setClock( clock )\
6670 if clock <= 0 then\
6671 self.clock = 0\
6672 elseif clock >= self.duration then\
6673 self.clock = self.duration\
6674 else\
6675 self.clock = clock\
6676 end\
6677\
6678 self:performEasing()\
6679 return self.clock >= self.duration\
6680end\
6681\
6682--[[\
6683 @static\
6684 @desc Binds the function 'easingFunction' to 'easingName'. Whenever an animation that uses easing of type 'easingName' is updated, this function will be called to calculate the value\
6685 @param <string - easingName>, <function - easingFunction>\
6686 @return <Class Base - Tween>\
6687]]\
6688function Tween.static.addEasing( easingName, easingFunction )\
6689 if type( easingFunction ) ~= \"function\" then\
6690 return error \"Easing function must be of type 'function'\"\
6691 end\
6692\
6693 Tween.static.easing[ easingName ] = easingFunction\
6694 return Tween\
6695end\
6696\
6697configureConstructor {\
6698 orderedArguments = { \"object\", \"name\", \"property\", \"final\", \"duration\", \"easing\", \"promise\" },\
6699 requiredArguments = { \"object\", \"name\", \"property\", \"final\", \"duration\" },\
6700 argumentTypes = {\
6701 name = \"string\",\
6702 property = \"string\",\
6703 final = \"number\",\
6704 duration = \"number\",\
6705 promise = \"function\"\
6706 }\
6707}\
6708",
6709["XMLLexer.ti"]="class \"XMLLexer\" extends \"Lexer\" {\
6710 openTag = false;\
6711 definingAttribute = false;\
6712 currentAttribute = false;\
6713}\
6714\
6715--[[\
6716 @instance\
6717 @desc Converts the stream into tokens by way of pattern matching\
6718]]\
6719function XMLLexer:tokenize()\
6720 self:trimStream()\
6721 local stream, openTag, currentAttribute, definingAttribute = self:trimStream(), self.openTag, self.currentAttribute, self.definingAttribute\
6722 local first = stream:sub( 1, 1 )\
6723\
6724 if stream:find \"^<(%w+)\" then\
6725 self:pushToken({type = \"XML_OPEN\", value = self:consumePattern \"^<(%w+)\"})\
6726 self.openTag = true\
6727 elseif stream:find \"^</(%w+)>\" then\
6728 self:pushToken({type = \"XML_END\", value = self:consumePattern \"^</(%w+)>\"})\
6729 self.openTag = false\
6730 elseif stream:find \"^/>\" then\
6731 self:pushToken({type = \"XML_END_CLOSE\"})\
6732 self:consume( 2 )\
6733 self.openTag = false\
6734 elseif openTag and stream:find \"^%w+\" then\
6735 self:pushToken({type = definingAttribute and \"XML_ATTRIBUTE_VALUE\" or \"XML_ATTRIBUTE\", value = self:consumePattern \"^%w+\"})\
6736\
6737 if not definingAttribute then\
6738 self.currentAttribute = true\
6739 return\
6740 end\
6741 elseif not openTag and stream:find \"^([^<]+)\" then\
6742 local content = self:consumePattern \"^([^<]+)\"\
6743\
6744 local newlines = select( 2, content:gsub(\"\\n\", \"\") )\
6745 if newlines then self:newline( newlines ) end\
6746\
6747 self:pushToken({type = \"XML_CONTENT\", value = content })\
6748 elseif first == \"=\" then\
6749 self:pushToken({type = \"XML_ASSIGNMENT\", value = \"=\"})\
6750 self:consume( 1 )\
6751\
6752 if currentAttribute then\
6753 self.definingAttribute = true\
6754 end\
6755\
6756 return\
6757 elseif first == \"'\" or first == \"\\\"\" then\
6758 self:pushToken({type = definingAttribute and \"XML_STRING_ATTRIBUTE_VALUE\" or \"XML_STRING\", value = self:consumeString( first )})\
6759 elseif first == \">\" then\
6760 self:pushToken({type = \"XML_CLOSE\"})\
6761 self.openTag = false\
6762 self:consume( 1 )\
6763 else\
6764 self:throw(\"Unexpected block '\"..stream:match(\"(.-)%s\")..\"'\")\
6765 end\
6766\
6767 if self.currentAttribute then self.currentAttribute = false end\
6768 if self.definingAttribute then self.definingAttribute = false end\
6769end\
6770",
6771["MTextDisplay.ti"]="--[[\
6772 This mixin \"is\" designed to be used by nodes that wish to display formatted text (e.g: Button, TextContainer).\
6773 The 'drawText' function should be called from the node during draw time.\
6774]]\
6775\
6776local string_len, string_find, string_sub, string_gsub, string_match = string.len, string.find, string.sub, string.gsub, string.match\
6777\
6778class \"MTextDisplay\" abstract() {\
6779 lineConfig = {\
6780 lines = false;\
6781 alignedLines = false;\
6782 offsetY = 0;\
6783 };\
6784\
6785 verticalPadding = 0;\
6786 horizontalPadding = 0;\
6787\
6788 verticalAlign = \"top\";\
6789 horizontalAlign = \"left\";\
6790}\
6791\
6792--[[\
6793 @constructor\
6794 @desc Registers properties used by this class \"with\" the theme handler if the object mixes in 'MThemeable'\
6795]]\
6796function MTextDisplay:MTextDisplay()\
6797 if Titanium.mixesIn( self, \"MThemeable\" ) then\
6798 self:register( \"text\", \"verticalAlign\", \"horizontalAlign\", \"verticalPadding\", \"horizontalPadding\" )\
6799 end\
6800end\
6801\
6802--[[\
6803 @instance\
6804 @desc Generates a table of text lines by wrapping on newlines or when the line gets too long.\
6805]]\
6806function MTextDisplay:wrapText()\
6807 local text, width, lines = self.text, self.width, {}\
6808\
6809 while text and string_len( text ) > 0 do\
6810 local section, pre, post = string_sub( text, 1, width )\
6811\
6812 if string_find( section, \"\\n\" ) then\
6813 pre, post = string_match( text, \"(.-)\\n%s*(.*)$\" )\
6814 elseif string_len( text ) <= width then\
6815 pre = text\
6816 else\
6817 local lastSpace = string_find( section, \"%s[%S]*$\" )\
6818\
6819 pre = lastSpace and string_gsub( string_sub( text, 1, lastSpace - 1 ), \"%s+$\", \"\" ) or section\
6820 post = lastSpace and string_sub( text, lastSpace + 1 ) or string_sub( text, width + 1 )\
6821 end\
6822\
6823 lines[ #lines + 1 ], text = pre, post\
6824 end\
6825\
6826 self.lineConfig.lines = lines\
6827end\
6828\
6829--[[\
6830 @instance\
6831 @desc Uses 'wrapText' to generate the information required to draw the text to the canvas correctly.\
6832]]\
6833function MTextDisplay:drawText( bg, tc )\
6834 local lines = self.lineConfig.lines\
6835 if not lines then\
6836 self:wrapText()\
6837 lines = self.lineConfig.lines\
6838 end\
6839\
6840 local vPadding, hPadding = self.verticalPadding, self.horizontalPadding\
6841\
6842 local yOffset, xOffset = vPadding, hPadding\
6843 local vAlign, hAlign = self.verticalAlign, self.horizontalAlign\
6844 local width, height = self.width, self.height\
6845\
6846 if vAlign == \"centre\" then\
6847 yOffset = math.floor( ( height / 2 ) - ( #lines / 2 ) + .5 ) + vPadding\
6848 elseif vAlign == \"bottom\" then\
6849 yOffset = height - #lines - vPadding\
6850 end\
6851\
6852 local canvas, line = self.canvas\
6853 for i = 1, #lines do\
6854 local line, xOffset = lines[ i ], hPadding\
6855 if hAlign == \"centre\" then\
6856 xOffset = math.floor( width / 2 - ( #line / 2 ) + .5 )\
6857 elseif hAlign == \"right\" then\
6858 xOffset = width - #line - hPadding + 1\
6859 end\
6860\
6861 canvas:drawTextLine( xOffset + 1, i + yOffset, line, tc, bg )\
6862 end\
6863end\
6864\
6865configureConstructor {\
6866 argumentTypes = {\
6867 verticalPadding = \"number\",\
6868 horizontalPadding = \"number\",\
6869\
6870 verticalAlign = \"string\",\
6871 horizontalAlign = \"string\",\
6872\
6873 text = \"string\"\
6874 }\
6875}\
6876",
6877["GenericEvent.ti"]="--[[\
6878 The GenericEvent class \"is\" spawned when an event that Titanium doesn't understand is caught in the Application event loop.\
6879\
6880 If you wish to spawn another sort of class \"when\" a certain event is caught, consider using `Event.static.bindEvent`.\
6881]]\
6882\
6883class \"GenericEvent\" extends \"Event\"\
6884\
6885--[[\
6886 @constructor\
6887 @desc Constructs the GenericEvent instance by storing all passed arguments in 'data'. The first index (1) of data is stored inside 'name'\
6888 @param <string - name>, [var - arg1], ...\
6889]]\
6890function GenericEvent:__init__( ... )\
6891 local args = { ... }\
6892\
6893 self.name = args[ 1 ]\
6894 self.main = self.name:upper()\
6895\
6896 self.data = args\
6897end\
6898",
6899["MPropertyManager.ti"]="--[[\
6900 Tracks property changes and invokes custom callbacks when they change.\
6901\
6902 Note: Only supports watching of arguments that have had their types set via `configure`.\
6903]]\
6904\
6905class \"MPropertyManager\" abstract() {\
6906 watching = {};\
6907 foreignWatchers = {};\
6908 links = {};\
6909 binds = {};\
6910}\
6911\
6912--[[\
6913 @constructor\
6914 @desc Hooks into all properties whose types have been defined. Un-hooked arguments cannot be watched.\
6915]]\
6916function MPropertyManager:MPropertyManager()\
6917 local properties = Titanium.getClass( self.__type ):getRegistry().constructor\
6918 if not ( properties or properties.argumentTypes ) then return end\
6919\
6920 for property in pairs( properties.argumentTypes ) do\
6921 local setterName = Titanium.getSetterName( property )\
6922 local oldSetter = self.raw[ setterName ]\
6923\
6924 self[ setterName ] = function( instance, value )\
6925 value = self:updateWatchers( property, value )\
6926\
6927 if oldSetter then\
6928 oldSetter( self, instance, value )\
6929 else\
6930 self[ property ] = value\
6931 end\
6932 end\
6933 end\
6934\
6935 -- Destroys local and foreign watcher instructions\
6936 self:on(\"remove\", function( instance )\
6937 self:unwatchForeignProperty \"*\"\
6938 self:unwatchProperty( \"*\", false, true )\
6939 end)\
6940end\
6941\
6942--[[\
6943 @instance\
6944 @desc Invokes the callback function of any watching links, passing the instance and value.\
6945 @param <string - property>, [var - value]\
6946 @return [var - value]\
6947]]\
6948function MPropertyManager:updateWatchers( property, value )\
6949 local function updateWatchers( prop )\
6950 local watchers = self.watching[ prop ]\
6951 if watchers then\
6952 for i = 1, #watchers do\
6953 local newVal = watchers[ i ][ 1 ]( self, prop, value )\
6954\
6955 if newVal ~= nil then\
6956 value = newVal\
6957 end\
6958 end\
6959 end\
6960 end\
6961\
6962 if property == \"*\" then\
6963 for prop in pairs( self.watching ) do updateWatchers( prop ) end\
6964 else\
6965 updateWatchers( property )\
6966 end\
6967\
6968 return value\
6969end\
6970\
6971--[[\
6972 @instance\
6973 @desc Adds a watch instruction on 'object' for 'property'. The instruction is logged in 'foreignWatchers' for future modification (ie: destruction)\
6974 @param <string - property>, <Instance - object>, <function - callback>, [string - name]\
6975]]\
6976function MPropertyManager:watchForeignProperty( property, object, callback, name )\
6977 if object == self then\
6978 return error \"Target object is not foreign. Select a foreign object or use :watchProperty\"\
6979 end\
6980\
6981 if not self.foreignWatchers[ property ] then self.foreignWatchers[ property ] = {} end\
6982 table.insert( self.foreignWatchers[ property ], object )\
6983\
6984 object:watchProperty( property, callback, name, self )\
6985end\
6986\
6987--[[\
6988 @instance\
6989 @desc Destroys the watch instruction for 'property'. If 'property' is '*', all property watchers are removed. If 'object' is given, only foreign links towards 'object' will be removed.\
6990 @param <string - property>, [Instance - object]\
6991]]\
6992function MPropertyManager:unwatchForeignProperty( property, object, name )\
6993 local function unwatchProp( prop )\
6994 local foreignWatchers = self.foreignWatchers[ prop ]\
6995\
6996 if foreignWatchers then\
6997 for i = #foreignWatchers, 1, -1 do\
6998 if not object or foreignWatchers[ i ] == object then\
6999 foreignWatchers[ i ]:unwatchProperty( prop, name, true )\
7000 table.remove( foreignWatchers, i )\
7001 end\
7002 end\
7003 end\
7004 end\
7005\
7006 if property == \"*\" then\
7007 for prop in pairs( self.foreignWatchers ) do unwatchProp( prop ) end\
7008 else\
7009 unwatchProp( property )\
7010 end\
7011end\
7012\
7013--[[\
7014 @instance\
7015 @desc Removes headless references of 'property' to foreign links for 'object'. Used when the foreign target (object) has severed connection and traces must be removed from the creator (self).\
7016 @param <string - property>, <string - object>\
7017]]\
7018function MPropertyManager:destroyForeignLink( property, object )\
7019 local watching = self.foreignWatchers[ property ]\
7020 if not watching then return end\
7021\
7022 for i = #watching, 1, -1 do\
7023 if watching[ i ] == object then\
7024 table.remove( watching, i )\
7025 end\
7026 end\
7027end\
7028\
7029--[[\
7030 @instance\
7031 @desc Instructs this object to call 'callback' when 'property' changes\
7032 @param <string - property>, <function - callback>, [string - name], [boolean - foreignOrigin]\
7033]]\
7034function MPropertyManager:watchProperty( property, callback, name, foreignOrigin )\
7035 if name then\
7036 self:unwatchProperty( property, name )\
7037 end\
7038\
7039 if not self.watching[ property ] then self.watching[ property ] = {} end\
7040 table.insert( self.watching[ property ], { callback, name, foreignOrigin } )\
7041end\
7042\
7043--[[\
7044 @instance\
7045 @desc Removes watch instructions for 'property'. If 'name' is given, only watch instructions with that name will be removed.\
7046 If 'foreign' is true, watch instructions marked as originating from a foreign source will also be removed - else, only local instructions will be removed.\
7047 If 'preserveForeign' and 'foreign' are true, foreign links will be removed, however they will NOT be disconnected from their origin\
7048 @param <string - property>, [string - name], [boolean - foreign], [boolean - preserveForeign]\
7049]]\
7050function MPropertyManager:unwatchProperty( property, name, foreign, preserveForeign )\
7051 local function unwatchProp( prop )\
7052 local watching = self.watching[ prop ]\
7053\
7054 if watching then\
7055 for i = #watching, 1, -1 do\
7056 if ( not name or watching[ i ][ 2 ] == name ) and ( foreign and watching[ i ][ 3 ] or ( not foreign and not watching[ i ][ 3 ] ) ) then\
7057 if foreign and not preserveForeign then\
7058 watching[ i ][ 3 ]:destroyForeignLink( prop, self )\
7059 end\
7060\
7061 table.remove( watching, i )\
7062 end\
7063 end\
7064 end\
7065 end\
7066\
7067 if property == \"*\" then\
7068 for prop in pairs( self.watching ) do unwatchProp( prop ) end\
7069 else\
7070 unwatchProp( property )\
7071 end\
7072end\
7073\
7074--[[\
7075 @instance\
7076 @desc Links properties given to 'target'. Properties can consist of tables or string values. If table, the first index represents the name of the foreign property to link to (belonging to 'target') and the second the local property to bind (belongs to 'self')\
7077 If the property is a string, the foreign property and local property match and a simple bind is produced\
7078 @param <Instance - target>, <var - properties>\
7079 @return <Instance - self>\
7080]]\
7081function MPropertyManager:linkProperties( target, ... )\
7082 local links = self.links\
7083 local function createLink( foreignProperty, localProperty )\
7084 localProperty = localProperty or foreignProperty\
7085\
7086 if self.links[ localProperty ] then\
7087 return error(\"Failed to link foreign property '\"..tostring(foreignProperty)..\"' from '\"..tostring(target)..\"' to local property '\"..tostring(localProperty)..\"'. A link already exists for this local property, remove that link before linking\")\
7088 end\
7089\
7090 self:watchForeignProperty( foreignProperty, target, function( _, __, value )\
7091 self[ localProperty ] = value\
7092 end, \"PROPERTY_LINK_\" .. self.__ID )\
7093\
7094 links[ localProperty ], self[ localProperty ] = target, target[ foreignProperty ]\
7095 end\
7096\
7097 local properties = { ... }\
7098 for i = 1, #properties do\
7099 local prop = properties[ i ]\
7100 if type( prop ) == \"table\" then createLink( prop[ 1 ], prop[ 2 ] ) else createLink( prop ) end\
7101 end\
7102\
7103 return self\
7104end\
7105\
7106--[[\
7107 @instance\
7108 @desc Creates a dynamic property link to self and all provided arguments. Can be removed using 'unlinkProperties'\
7109 @param <string - property>, <table - arguments>, <string - equation>\
7110]]\
7111function MPropertyManager:dynamicallyLinkProperty( property, arguments, equation )\
7112 if self.links[ property ] then\
7113 return error(\"Failed to create dynamic link for '\"..property..\"'. A link already exists for this property\")\
7114 elseif self.binds[ property ] then\
7115 return error(\"Lingering dynamic bind found for property '\"..property..\"'. Failed to bind property\")\
7116 end\
7117\
7118 self.links[ property ], self.binds[ property ] = true, DynamicValue( self, property, arguments, equation )\
7119end\
7120\
7121--[[\
7122 @instance\
7123 @desc Removes the property link for foreign properties ..., bound to 'target'. The properties provided represent the foreign property that is bound to, not the local property.\
7124 @param <Instance - target>, <... - foreignProperties>\
7125 @return <Instance - self>\
7126]]\
7127function MPropertyManager:unlinkProperties( target, ... )\
7128 local properties, links, binds = { ... }, self.links, self.binds\
7129 for i = 1, #properties do\
7130 local prop = properties[ i ]\
7131 if binds[ prop ] then\
7132 binds[ prop ]:detach()\
7133 binds[ prop ], links[ prop ] = nil, nil\
7134 else\
7135 self:unwatchForeignProperty( prop, target, \"PROPERTY_LINK_\" .. self.__ID )\
7136\
7137 if links[ prop ] == target then\
7138 links[ prop ] = nil\
7139 end\
7140 end\
7141 end\
7142\
7143 return self\
7144end\
7145",
7146["Event.ti"]="class \"Event\" abstract() {\
7147 static = {\
7148 matrix = {}\
7149 }\
7150}\
7151\
7152--[[\
7153 @instance\
7154 @desc Returns true if the event name (index '1' of data) matches the parameter 'event' provided\
7155 @param <string - event>\
7156 @return <boolean - eq>\
7157]]\
7158function Event:is( event )\
7159 return self.name == event\
7160end\
7161\
7162--[[\
7163 @instance\
7164 @desc Sets the 'handled' paramater to true. This indicates the event has been used and should not be used.\
7165]]\
7166function Event:setHandled( handled )\
7167 self.raw.handled = handled\
7168end\
7169\
7170--[[\
7171 @static\
7172 @desc Instantiates an event object if an entry for that event type is present inside the event matrix.\
7173 @param <string - eventName>, [vararg - eventData]\
7174 @return <Instance*>\
7175\
7176 *Note: The type of instance is variable. If an entry is present inside the matrix that class \"will\" be\
7177 instantiated, otherwise a 'GenericEvent' instance will be returned.\
7178]]\
7179function Event.static.spawn( name, ... )\
7180 return ( Event.matrix[ name ] or GenericEvent )( name, ... )\
7181end\
7182\
7183--[[\
7184 @static\
7185 @desc Adds an entry to the event matrix. When an event named 'name' is caught, the class 'clasType' will be instantiated\
7186 @param <string - name>, <string - classType>\
7187]]\
7188function Event.static.bindEvent( name, classType )\
7189 Event.matrix[ name ] = Titanium.getClass( classType ) or error( \"Class '\"..tostring( classType )..\"' cannot be found\" )\
7190end\
7191\
7192--[[\
7193 @static\
7194 @desc Removes an entry from the event matrix.\
7195 @param <string - name>\
7196]]\
7197function Event.static.unbindEvent( name )\
7198 Event.matrix[ name ] = nil\
7199end\
7200",
7201["DynamicValue.ti"]="class \"DynamicValue\" {\
7202 propertyValues = {};\
7203 properties = {};\
7204}\
7205\
7206--[[\
7207 @constructor\
7208 @desc Creates watcher instructions towards 'target' for each property linked\
7209 @param <Instance - target>, <string - property>, <table - properties>, <string - equation>\
7210]]\
7211function DynamicValue:__init__( ... )\
7212 self:resolve( ... )\
7213 self:attach()\
7214\
7215 local reg = Titanium.getClass( self.target.__type ):getRegistry().constructor\
7216 if reg and reg.argumentTypes then\
7217 self.type = reg.argumentTypes[ self.property ]\
7218 end\
7219\
7220 self:solve()\
7221end\
7222\
7223--[[\
7224 @instance\
7225 @desc Attach watch instructions to each required argument\
7226]]\
7227function DynamicValue:attach()\
7228 local properties = self.properties\
7229 for i = 1, #properties do\
7230 local obj, prop = properties[ i ][ 2 ], properties[ i ][ 1 ]\
7231\
7232 obj:watchProperty( prop, function( _, __, val )\
7233 self.propertyValues[ i ] = val\
7234 self:solve()\
7235 end, \"DYNAMIC_LINK_\" .. self.__ID )\
7236\
7237 self.propertyValues[ i ] = obj[ prop ]\
7238 end\
7239end\
7240\
7241--[[\
7242 @instance\
7243 @desc Detaches the watcher instructions towards the targets of the dynamic value\
7244]]\
7245function DynamicValue:detach()\
7246 local properties = self.properties\
7247 for i = 1, #properties do\
7248 local prop = properties[ i ]\
7249 prop[ 2 ]:unwatchProperty( prop[ 1 ], \"DYNAMIC_LINK_\" .. self.__ID )\
7250 end\
7251end\
7252\
7253--[[\
7254 @instance\
7255 @desc Solves the 'equation' by inserting the values fetched off of linked targets\
7256]]\
7257function DynamicValue:solve()\
7258 local fn, err = loadstring( self.equation )\
7259 if not fn then return error(\"Failed to solve dynamic value equation (\"..tostring( eq )..\"). Parse exception: \" .. tostring( err )) end\
7260\
7261 local ok, val = pcall( fn, self.propertyValues )\
7262 if not ok then return error(\"Failed to solve dyamic value equation (\"..tostring( eq )..\"). Runtime exception: \" .. tostring( val )) end\
7263\
7264 self.target[ self.property ] = XMLParser.convertArgType( val, self.type )\
7265end\
7266\
7267configureConstructor {\
7268 orderedArguments = { \"target\", \"property\", \"properties\", \"equation\" },\
7269 argumentTypes = {\
7270 property = \"string\",\
7271 properties = \"table\",\
7272 equation = \"string\"\
7273 },\
7274 requiredArguments = true\
7275}\
7276",
7277["MFocusable.ti"]="--[[\
7278 A focusable object is an object that after a mouse_click and a mouse_up event occur on the object is 'focused'.\
7279\
7280 An 'input' is a good example of a focusable node, it is activatable (while being clicked) but it also focusable (allows you to type after being focused).\
7281]]\
7282\
7283class \"MFocusable\" abstract() {\
7284 focused = false;\
7285}\
7286\
7287function MFocusable:MFocusable()\
7288 if Titanium.mixesIn( self, \"MThemeable\" ) then\
7289 self:register(\"focused\", \"focusedColour\", \"focusedBackgroundColour\")\
7290 end\
7291end\
7292\
7293function MFocusable:setEnabled( enabled )\
7294 self.super:setEnabled( enabled )\
7295\
7296 if not enabled and self.focused then\
7297 self:unfocus()\
7298 end\
7299end\
7300\
7301function MFocusable:setFocused( focused )\
7302 local raw = self.raw\
7303 if raw.focused == focused then return end\
7304\
7305 self.changed = true\
7306 self.focused = focused\
7307end\
7308\
7309function MFocusable:focus()\
7310 if not self.enabled then return end\
7311\
7312 if self.application then self.application:focusNode( self ) end\
7313 self.focused = true\
7314end\
7315\
7316function MFocusable:unfocus()\
7317 if self.application then self.application:unfocusNode( self ) end\
7318 self.focused = false\
7319end\
7320\
7321configureConstructor {\
7322 argumentTypes = {\
7323 focusedBackgroundColour = \"colour\",\
7324 focusedColour = \"colour\",\
7325 focused = \"boolean\"\
7326 }\
7327} alias {\
7328 focusedColor = \"focusedColour\",\
7329 focusedBackgroundColor = \"focusedBackgroundColour\"\
7330}\
7331",
7332["QueryLexer.ti"]="class \"QueryLexer\" extends \"Lexer\"\
7333\
7334function QueryLexer:tokenize()\
7335 if self.stream:find \"^%s\" and not self.inCondition then\
7336 self:pushToken { type = \"QUERY_SEPERATOR\" }\
7337 end\
7338\
7339 local stream = self:trimStream()\
7340\
7341 if self.inCondition then\
7342 self:tokenizeCondition( stream )\
7343 elseif stream:find \"^%b[]\" then\
7344 self:pushToken { type = \"QUERY_COND_OPEN\" }\
7345 self:consume( 1 )\
7346\
7347 self.inCondition = true\
7348 elseif stream:find \"^%,\" then\
7349 self:pushToken { type = \"QUERY_END\", value = self:consumePattern \"^%,\" }\
7350 elseif stream:find \"^>\" then\
7351 self:pushToken { type = \"QUERY_DIRECT_PREFIX\", value = self:consumePattern \"^>\" }\
7352 elseif stream:find \"^#[^%s%.#%[%,]*\" then\
7353 self:pushToken { type = \"QUERY_ID\", value = self:consumePattern \"^#([^%s%.#%[]*)\" }\
7354 elseif stream:find \"^%.[^%s#%[%,]*\" then\
7355 self:pushToken { type = \"QUERY_CLASS\", value = self:consumePattern \"^%.([^%s%.#%[]*)\" }\
7356 elseif stream:find \"^[^,%s#%.%[]*\" then\
7357 self:pushToken { type = \"QUERY_TYPE\", value = self:consumePattern \"^[^,%s#%.%[]*\" }\
7358 else\
7359 self:throw(\"Unexpected block '\"..stream:match(\"(.-)%s\")..\"'\")\
7360 end\
7361end\
7362\
7363function QueryLexer:tokenizeCondition( stream )\
7364 local first = stream:sub( 1, 1 )\
7365 if stream:find \"%b[]\" then\
7366 self:throw( \"Nested condition found '\"..tostring( stream:match \"%b[]\" )..\"'\" )\
7367 elseif stream:find \"^%b''\" or stream:find '^%b\"\"' then\
7368 local cnt = self:consumePattern( first == \"'\" and \"^%b''\" or '^%b\"\"' ):sub( 2, -2 )\
7369 if cnt:find \"%b''\" or cnt:find '%b\"\"' then\
7370 self:throw( \"Nested string found inside '\"..tostring( cnt )..\"'\" )\
7371 end\
7372\
7373 self:pushToken { type = \"QUERY_COND_STRING_ENTITY\", value = cnt }\
7374 elseif stream:find \"^%w+\" then\
7375 self:pushToken { type = \"QUERY_COND_ENTITY\", value = self:consumePattern \"^%w+\" }\
7376 elseif stream:find \"^%,\" then\
7377 self:pushToken { type = \"QUERY_COND_SEPERATOR\" }\
7378 self:consume( 1 )\
7379 elseif stream:find \"^[%p~]+\" then\
7380 self:pushToken { type = \"QUERY_COND_SYMBOL\", value = self:consumePattern \"^[%p~]+\" }\
7381 elseif stream:find \"^%]\" then\
7382 self:pushToken { type = \"QUERY_COND_CLOSE\" }\
7383 self:consume( 1 )\
7384 self.inCondition = false\
7385 else\
7386 self:throw(\"Invalid condition syntax. Expected property near '\"..tostring( stream:match \"%S*\" )..\"'\")\
7387 end\
7388end\
7389",
7390["MTogglable.ti"]="--[[\
7391 A small mixin \"to\" avoid rewriting code used by nodes that can be toggled on or off.\
7392]]\
7393\
7394class \"MTogglable\" abstract() {\
7395 toggled = false;\
7396\
7397 toggledColour = colours.red;\
7398 toggledBackgroundColour = colours.white;\
7399}\
7400\
7401--[[\
7402 @constructor\
7403 @desc Registers properties used by this class \"with\" the theme handler if the object mixes in 'MThemeable'\
7404]]\
7405function MTogglable:MTogglable()\
7406 if Titanium.mixesIn( self, \"MThemeable\" ) then\
7407 self:register(\"toggled\", \"toggledColour\", \"toggledBackgroundColour\")\
7408 end\
7409end\
7410\
7411--[[\
7412 @instance\
7413 @desc 'toggled' to the opposite of what it currently is (toggles)\
7414]]\
7415function MTogglable:toggle( ... )\
7416 self:setToggled( not self.toggled, ... )\
7417end\
7418\
7419--[[\
7420 @instance\
7421 @desc Sets toggled to 'toggled' and changed to 'true' when the 'toggled' param doesn't match the current value of toggled.\
7422 @param <boolean - toggled>, [vararg - onToggleArguments]\
7423]]\
7424function MTogglable:setToggled( toggled, ... )\
7425 if self.toggled ~= toggled then\
7426 self.raw.toggled = toggled\
7427 self.changed = true\
7428\
7429 self:executeCallbacks( \"toggle\", ... )\
7430 end\
7431end\
7432\
7433configureConstructor {\
7434 argumentTypes = {\
7435 toggled = \"boolean\",\
7436 toggledColour = \"colour\",\
7437 toggledBackgroundColour = \"colour\"\
7438 }\
7439} alias {\
7440 toggledColor = \"toggledColour\",\
7441 toggledBackgroundColor = \"toggledBackgroundColour\"\
7442}\
7443",
7444["TermCanvas.ti"]="--[[\
7445 The TermCanvas is an object that draws it's buffer directly to the ComputerCraft term object, unlike the NodeCanvas.\
7446\
7447 The TermCanvas should be used by high level objects, like 'Application'. Nodes should not be drawing directly to the term object.\
7448 If your object needs to draw to the canvas this class \"should\" be used.\
7449\
7450 Unlike NodeCanvas, TermCanvas has no drawing functions as it's purpose is not to generate the buffer, just draw it to the term object.\
7451 Nodes generate their content and store it in your buffer (and theirs aswell).\
7452--]]\
7453\
7454local hex = {}\
7455for i = 0, 15 do\
7456 hex[2 ^ i] = (\"%x\"):format( i ) -- %x = lowercase hexadecimal\
7457 hex[(\"%x\"):format( i )] = 2 ^ i\
7458end\
7459\
7460local tableConcat = table.concat\
7461\
7462class \"TermCanvas\" extends \"Canvas\" {\
7463 static = { hex = hex };\
7464}\
7465\
7466function TermCanvas:__init__( owner )\
7467 self:super( owner )\
7468\
7469 self.raw.X = owner.raw.X\
7470 self.raw.Y = owner.raw.Y\
7471end\
7472\
7473function TermCanvas:draw( force )\
7474 local owner = self.owner\
7475 local buffer, last = self.buffer, self.last\
7476 local X, Y, width, height = owner.X, owner.Y - 1, self.width, self.height\
7477 local colour, backgroundChar, backgroundTextColour, backgroundColour = self.colour, self.backgroundChar, self.backgroundTextColour, self.backgroundColour\
7478\
7479 local position, px, lpx = 1\
7480 for y = 1, height do\
7481 local changed\
7482\
7483 for x = 1, width do\
7484 px, lpx = buffer[ position ], last[ position ]\
7485\
7486 if force or not lpx or ( px[ 1 ] ~= lpx[ 1 ] or px[ 2 ] ~= lpx[ 2 ] or px[ 3 ] ~= lpx[ 3 ] ) then\
7487 changed = true\
7488\
7489 position = position - ( x - 1 )\
7490 break\
7491 end\
7492\
7493 position = position + 1\
7494 end\
7495\
7496 if changed then\
7497 local rowText, rowColour, rowBackground, pixel = {}, {}, {}\
7498\
7499 for x = 1, width do\
7500 pixel = buffer[ position ]\
7501 last[ position ] = pixel\
7502\
7503 local c, fg, bg = pixel[1], pixel[2], pixel[3]\
7504\
7505 rowColour[ x ] = hex[ type(fg) == \"number\" and fg ~= 0 and fg or colour or 1 ]\
7506 rowBackground[ x ] = hex[ type(bg) == \"number\" and bg ~= 0 and bg or backgroundColour or 32768 ]\
7507 if c then\
7508 rowText[ x ] = c or backgroundChar or \" \"\
7509 else\
7510 rowText[ x ] = backgroundChar or \" \"\
7511 rowColour[ x ] = hex[ backgroundTextColour or 1 ]\
7512 end\
7513\
7514 position = position + 1\
7515 end\
7516\
7517 term.setCursorPos( X, y + Y )\
7518 term.blit( tableConcat( rowText ), tableConcat( rowColour ), tableConcat( rowBackground ) )\
7519 end\
7520 end\
7521end\
7522",
7523["MCallbackManager.ti"]="--[[\
7524 The callback manager is a mixin \"that\" can be used by classes that want to provide an easy way for a developer to assign actions on certain conditions.\
7525\
7526 These conditions may include node specific callbacks, like a button click or input submission.\
7527]]\
7528\
7529class \"MCallbackManager\" abstract() {\
7530 callbacks = {}\
7531}\
7532\
7533--[[\
7534 @instance\
7535 @desc Assigns a function 'fn' to 'callbackName'.\
7536 @param <string - name>, <function - fn>, [string - id]\
7537]]\
7538function MCallbackManager:on( callbackName, fn, id )\
7539 if not ( type( callbackName ) == \"string\" and type( fn ) == \"function\" ) or ( id and type( id ) ~= \"string\" ) then\
7540 return error \"Expected string, function, [string]\"\
7541 end\
7542\
7543 local callbacks = self.callbacks\
7544 if not callbacks[ callbackName ] then callbacks[ callbackName ] = {} end\
7545\
7546 table.insert( callbacks[ callbackName ], { fn, id } )\
7547\
7548 return self\
7549end\
7550\
7551--[[\
7552 @instance\
7553 @desc Removes all callbacks for a certain condition. If an id is provided only callbacks matching that id will be executed.\
7554 @param <string - callbackName>, [string - id]\
7555]]\
7556function MCallbackManager:off( callbackName, id )\
7557 if id then\
7558 local callbacks = self.callbacks[ callbackName ]\
7559\
7560 if callbacks then\
7561 for i = #callbacks, 1, -1 do\
7562 if callbacks[ i ][ 2 ] == id then\
7563 table.remove( callbacks, i )\
7564 end\
7565 end\
7566 end\
7567 else self.callbacks[ callbackName ] = nil end\
7568\
7569 return self\
7570end\
7571\
7572--[[\
7573 @instance\
7574 @desc Executes all assigned functions for 'callbackName' with 'self' and the arguments passed to this function.\
7575 @param <string - callbackName>, [vararg - ...]\
7576]]\
7577function MCallbackManager:executeCallbacks( callbackName, ... )\
7578 local callbacks = self.callbacks[ callbackName ]\
7579\
7580 if callbacks then\
7581 for i = 1, #callbacks do callbacks[ i ][ 1 ]( self, ... ) end\
7582 end\
7583end\
7584\
7585function MCallbackManager:canCallback( name )\
7586 return #self.callbacks[ name ] > 0\
7587end\
7588",
7589["MActivatable.ti"]="--[[\
7590 A mixin \"to\" reuse code commonly written when developing nodes that can be (de)activated.\
7591]]\
7592\
7593class \"MActivatable\" abstract() {\
7594 active = false;\
7595\
7596 activeColour = colours.white;\
7597 activeBackgroundColour = colours.cyan;\
7598}\
7599\
7600--[[\
7601 @constructor\
7602 @desc Registers properties used by this class \"with\" the theme handler if the object mixes in 'MThemeable'\
7603]]\
7604function MActivatable:MActivatable()\
7605 if Titanium.mixesIn( self, \"MThemeable\" ) then\
7606 self:register( \"active\", \"activeColour\", \"activeBackgroundColour\" )\
7607 end\
7608end\
7609\
7610--[[\
7611 @instance\
7612 @desc Sets the 'active' property to the 'active' argument passed. When the 'active' property changes the node will become 'changed'.\
7613 @param <boolean - active>\
7614]]\
7615function MActivatable:setActive( active )\
7616 local raw = self.raw\
7617 if raw.active == active then return end\
7618\
7619 raw.active = active\
7620 self:queueAreaReset()\
7621end\
7622\
7623configureConstructor {\
7624 argumentTypes = { active = \"boolean\", activeColour = \"colour\", activeBackgroundColour = \"colour\" }\
7625} alias {\
7626 activeColor = \"activeColour\",\
7627 activeBackgroundColor = \"activeBackgroundColour\"\
7628}\
7629",
7630["Lexer.ti"]="class \"Lexer\" abstract() {\
7631 static = {\
7632 escapeChars = {\
7633 a = \"\\a\",\
7634 b = \"\\b\",\
7635 f = \"\\f\",\
7636 n = \"\\n\",\
7637 r = \"\\r\",\
7638 t = \"\\t\",\
7639 v = \"\\v\"\
7640 }\
7641 };\
7642\
7643 stream = false;\
7644\
7645 tokens = {};\
7646\
7647 line = 1;\
7648 char = 1;\
7649}\
7650\
7651--[[\
7652 @constructor\
7653 @desc Constructs the Lexer instance by providing the instance with a 'stream'.\
7654 @param <string - stream>, [boolean - manual]\
7655]]\
7656function Lexer:__init__( stream, manual )\
7657 if type( stream ) ~= \"string\" then\
7658 return error \"Failed to initialise Lexer instance. Invalid stream paramater passed (expected string)\"\
7659 end\
7660 self.stream = stream\
7661\
7662 if not manual then\
7663 self:formTokens()\
7664 end\
7665end\
7666\
7667--[[\
7668 @instance\
7669 @desc This function is used to repeatedly call 'tokenize' until the stream has been completely consumed.\
7670]]\
7671function Lexer:formTokens()\
7672 while self.stream and self.stream:find \"%S\" do\
7673 self:tokenize()\
7674 end\
7675end\
7676\
7677--[[\
7678 @instance\
7679 @desc A simple function that is used to add a token to the instances 'tokens' table.\
7680 @param <table - token>\
7681]]\
7682function Lexer:pushToken( token )\
7683 local tokens = self.tokens\
7684\
7685 token.char = self.char\
7686 token.line = self.line\
7687 tokens[ #tokens + 1 ] = token\
7688end\
7689\
7690--[[\
7691 @instance\
7692 @desc Consumes the stream by 'amount'.\
7693]]\
7694function Lexer:consume( amount )\
7695 local stream = self.stream\
7696 self.stream = stream:sub( amount + 1 )\
7697\
7698 self.char = self.char + amount\
7699 return content\
7700end\
7701\
7702--[[\
7703 @instance\
7704 @desc Uses the Lua pattern provided to select text from the stream that matches the pattern. The text is then consumed from the stream (entire pattern, not just selected text)\
7705 @param <string - pattern>, [number - offset]\
7706]]\
7707function Lexer:consumePattern( pattern, offset )\
7708 local cnt = self.stream:match( pattern )\
7709\
7710 self:consume( select( 2, self.stream:find( pattern ) ) + ( offset or 0 ) )\
7711 return cnt\
7712end\
7713\
7714--[[\
7715 @instance\
7716 @desc Searches for the next occurence of 'opener'. Once found all text between the first two occurences is selected and consumed resulting in a XML_STRING token.\
7717 @param <char - opener>\
7718 @return <string - consumedString>\
7719]]\
7720function Lexer:consumeString( opener )\
7721 local stream, closingIndex = self.stream\
7722\
7723 if stream:find( opener, 2 ) then\
7724 local str, c, escaped = {}\
7725 for i = 2, #stream do\
7726 c = stream:sub( i, i )\
7727\
7728 if escaped then\
7729 str[ #str + 1 ] = Lexer.escapeChars[ c ] or c\
7730 escaped = false\
7731 elseif c == \"\\\\\" then\
7732 escaped = true\
7733 elseif c == opener then\
7734 self:consume( i )\
7735 return table.concat( str )\
7736 else\
7737 str[ #str + 1 ] = c\
7738 end\
7739 end\
7740 end\
7741\
7742 self:throw( \"Failed to lex stream. Expected string end (\"..opener..\")\" )\
7743end\
7744\
7745--[[\
7746 @instance\
7747 @desc Removes all trailing spaces from\
7748]]\
7749function Lexer:trimStream()\
7750 local stream = self.stream\
7751\
7752 local newLn = stream:match(\"^(\\n+)\")\
7753 if newLn then self:newline( #newLn ) end\
7754\
7755 local spaces = select( 2, stream:find \"^%s*%S\" )\
7756\
7757 self.stream = stream:sub( spaces )\
7758 self.char = self.char + spaces - 1\
7759\
7760 return self.stream\
7761end\
7762\
7763--[[\
7764 @instance\
7765 @desc Advanced 'line' by 'amount' (or 1) and sets 'char' back to zero\
7766]]\
7767function Lexer:newline( amount )\
7768 self.line = self.line + ( amount or 1 )\
7769 self.char = 0\
7770end\
7771\
7772--[[\
7773 @instance\
7774 @desc Throws error 'e' prefixed with information regarding current position and stores the error in 'exception' for later reference\
7775]]\
7776function Lexer:throw( e )\
7777 self.exception = \"Lexer (\" .. tostring( self.__type ) .. \") Exception at line '\"..self.line..\"', char '\"..self.char..\"': \"..e\
7778 return error( self.exception )\
7779end\
7780",
7781["ScrollContainer.ti"]="class \"ScrollContainer\" extends \"Container\" {\
7782 cache = {};\
7783\
7784 xScroll = 0;\
7785 yScroll = 0;\
7786\
7787 xScrollAllowed = true;\
7788 yScrollAllowed = true;\
7789 propagateMouse = true;\
7790\
7791 trayColour = 256;\
7792 scrollbarColour = 128;\
7793 activeScrollbarColour = colours.cyan;\
7794\
7795 mouse = {\
7796 selected = false;\
7797 origin = false;\
7798 };\
7799}\
7800\
7801function ScrollContainer:__init__( ... )\
7802 self:register( \"scrollbarColour\", \"activeScrollbarColour\", \"trayColour\" )\
7803 self:super( ... )\
7804end\
7805\
7806--[[ Event Listeners ]]--\
7807function ScrollContainer:onMouseClick( event, handled, within )\
7808 if handled or not within then return end\
7809\
7810 local cache, mouse, key = self.cache, self.mouse\
7811 local X, Y = event.X - self.X + 1, event.Y - self.Y + 1\
7812\
7813 if cache.yScrollActive and X == self.width and Y <= cache.displayHeight then\
7814 key = \"y\"\
7815 elseif cache.xScrollActive and Y == self.height and X <= cache.displayWidth then\
7816 key = \"x\"\
7817 else return end\
7818\
7819 local scrollFn = self[ \"set\"..key:upper()..\"Scroll\" ]\
7820 local edge, size = cache[ key .. \"ScrollPosition\" ], cache[ key .. \"ScrollSize\" ]\
7821 local cScale, dScale = cache[ \"content\" .. ( key == \"x\" and \"Width\" or \"Height\" ) ], cache[ \"display\" .. ( key == \"x\" and \"Width\" or \"Height\" ) ]\
7822\
7823 local rel = key == \"x\" and X or Y\
7824 if rel < edge then\
7825 event.handled = scrollFn( self, math.floor( cScale * ( rel / dScale ) - .5 ) )\
7826 elseif rel >= edge and rel <= edge + size - 1 then\
7827 mouse.selected, mouse.origin = key == \"x\" and \"h\" or \"v\", rel - edge + 1\
7828 elseif rel > edge + size - 1 then\
7829 event.handled = scrollFn( self, math.floor( cScale * ( ( rel - size + 1 ) / dScale ) - .5 ) )\
7830 end\
7831\
7832 self:cacheScrollbarPosition()\
7833 self.changed = true\
7834end\
7835\
7836function ScrollContainer:onMouseScroll( event, handled, within )\
7837 local cache, app = self.cache, self.application\
7838 if handled or not within or not ( cache.xScrollActive or cache.yScrollActive ) then return end\
7839\
7840 local isXScroll = ( cache.xScrollActive and ( not cache.yScrollActive or ( app:isPressed( keys.leftShift ) or app:isPressed( keys.rightShift ) ) ) )\
7841\
7842 event.handled = self[\"set\".. ( isXScroll and \"X\" or \"Y\" ) ..\"Scroll\"]( self, self[ ( isXScroll and \"x\" or \"y\" ) .. \"Scroll\" ] + event.button )\
7843 self:cacheScrollbarPosition()\
7844end\
7845\
7846function ScrollContainer:onMouseUp( event, handled, within )\
7847 if self.mouse.selected then\
7848 self.mouse.selected = false\
7849 self.changed = true\
7850 end\
7851end\
7852\
7853function ScrollContainer:onMouseDrag( event, handled, within )\
7854 local mouse, cache = self.mouse, self.cache\
7855 if handled or not mouse.selected then return end\
7856\
7857 local isV = mouse.selected == \"v\"\
7858 local key = isV and \"Y\" or \"X\"\
7859 local scaleKey = isV and \"Height\" or \"Width\"\
7860\
7861 event.handled = self[ \"set\" .. key .. \"Scroll\" ]( self, math.floor( cache[\"content\" .. scaleKey ] * ( ( ( event[ key ] - self[ key ] + 1 ) - mouse.origin ) / cache[\"display\" .. scaleKey ] ) - .5 ) )\
7862end\
7863\
7864function ScrollContainer:addNode( node, ... )\
7865 self.super:addNode( node, ... )\
7866\
7867 self:cacheContent()\
7868\
7869 return node\
7870end\
7871\
7872--[[ Core Functions ]]--\
7873function ScrollContainer:handle( eventObj )\
7874 local cache, isWithin = self.cache, eventObj.isWithin\
7875 local cloneEv\
7876\
7877 if eventObj.main == \"MOUSE\" then\
7878 eventObj.isWithin = eventObj:withinParent( self )\
7879 if ( not cache.yScrollActive or ( eventObj.X - self.X + 1 ) ~= self.width ) and ( not cache.xScrollActive or ( eventObj.Y - self.Y + 1 ) ~= self.height ) then\
7880 cloneEv = eventObj:clone( self )\
7881 cloneEv.Y = cloneEv.Y + self.yScroll\
7882 cloneEv.X = cloneEv.X + self.xScroll\
7883 end\
7884 else cloneEv = eventObj end\
7885\
7886 if cloneEv then self:shipEvent( cloneEv ) end\
7887 local r = self.super.super:handle( eventObj )\
7888\
7889 eventObj.isWithin = isWithin\
7890 return r == nil and true or r\
7891end\
7892\
7893function ScrollContainer:isNodeInBounds( node, width, height )\
7894 local left, top = node.X - self.xScroll, node.Y - self.yScroll\
7895\
7896 return not ( ( left + node.width ) < 1 or left > ( width or self.width ) or top > ( height or self.height ) or ( top + node.height ) < 1 )\
7897end\
7898\
7899function ScrollContainer:draw( force )\
7900 if self.changed or force then\
7901 self.super:draw( force, -self.xScroll, -self.yScroll )\
7902 self:drawScrollbars()\
7903 end\
7904end\
7905\
7906function ScrollContainer:drawScrollbars()\
7907 local cache, canvas = self.cache, self.canvas\
7908 local xEnabled, yEnabled = cache.xScrollActive, cache.yScrollActive\
7909\
7910 if xEnabled then\
7911 canvas:drawBox( 1, self.height, cache.displayWidth, 1, self.trayColour )\
7912 canvas:drawBox( cache.xScrollPosition, self.height, cache.xScrollSize, 1, self.mouse.selected == \"h\" and self.activeScrollbarColour or self.scrollbarColour )\
7913 end\
7914\
7915 if yEnabled then\
7916 canvas:drawBox( self.width, 1, 1, cache.displayHeight, self.trayColour )\
7917 canvas:drawBox( self.width, cache.yScrollPosition, 1, cache.yScrollSize, self.mouse.selected == \"v\" and self.activeScrollbarColour or self.scrollbarColour )\
7918 end\
7919\
7920 if yEnabled and xEnabled then\
7921 canvas:drawPoint( self.width, self.height, \" \", 1, self.trayColour )\
7922 end\
7923end\
7924\
7925function ScrollContainer:redrawArea( x, y, width, height )\
7926 self.super:redrawArea( x, y, width, height, -self.xScroll, -self.yScroll )\
7927end\
7928\
7929function ScrollContainer:setYScroll( yScroll )\
7930 local oY, cache = self.yScroll, self.cache\
7931 self.yScroll = math.max( 0, math.min( cache.contentHeight - cache.displayHeight, yScroll ) )\
7932\
7933 self:cacheScrollbarPosition()\
7934 if ( not self.propagateMouse ) or oY ~= self.yScroll then\
7935 return true\
7936 end\
7937end\
7938\
7939function ScrollContainer:setXScroll( xScroll )\
7940 local oX, cache = self.xScroll, self.cache\
7941 self.xScroll = math.max( 0, math.min( cache.contentWidth - cache.displayWidth, xScroll ) )\
7942\
7943 self:cacheScrollbarPosition()\
7944 if ( not self.propagateMouse ) or oX ~= self.xScroll then\
7945 return true\
7946 end\
7947end\
7948\
7949function ScrollContainer:setHeight( height )\
7950 self.super:setHeight( height )\
7951 self:cacheContent()\
7952end\
7953\
7954function ScrollContainer:setWidth( width )\
7955 self.super:setWidth( width )\
7956 self:cacheContent()\
7957end\
7958\
7959--[[ Caching Functions ]]--\
7960function ScrollContainer:cacheContent()\
7961 self:cacheContentSize()\
7962 self:cacheActiveScrollbars()\
7963end\
7964\
7965function ScrollContainer:cacheContentSize()\
7966 local w, h = 0, 0\
7967\
7968 local nodes, node = self.nodes\
7969 for i = 1, #nodes do\
7970 node = nodes[ i ]\
7971\
7972 w = math.max( node.X + node.width - 1, w )\
7973 h = math.max( node.Y + node.height - 1, h )\
7974 end\
7975\
7976 self.cache.contentWidth, self.cache.contentHeight = w, h\
7977end\
7978\
7979function ScrollContainer:cacheDisplaySize()\
7980 local cache = self.cache\
7981 cache.displayWidth, cache.displayHeight = self.width - ( cache.yScrollActive and 1 or 0 ), self.height - ( cache.xScrollActive and 1 or 0 )\
7982\
7983 self:cacheScrollbarSize()\
7984end\
7985\
7986function ScrollContainer:cacheActiveScrollbars()\
7987 local cache = self.cache\
7988 local cWidth, cHeight, sWidth, sHeight = cache.contentWidth, cache.contentHeight, self.width, self.height\
7989 local xAllowed, yAllowed = self.xScrollAllowed, self.yScrollAllowed\
7990\
7991 local horizontal, vertical\
7992 if ( cWidth > sWidth and xAllowed ) or ( cHeight > sHeight and yAllowed ) then\
7993 cache.xScrollActive, cache.yScrollActive = cWidth > sWidth - 1 and xAllowed, cHeight > sHeight - 1 and yAllowed\
7994 else\
7995 cache.xScrollActive, cache.yScrollActive = false, false\
7996 end\
7997\
7998 self:cacheDisplaySize()\
7999end\
8000\
8001function ScrollContainer:cacheScrollbarSize()\
8002 local cache = self.cache\
8003 cache.xScrollSize, cache.yScrollSize = math.floor( cache.displayWidth * ( cache.displayWidth / cache.contentWidth ) + .5 ), math.floor( cache.displayHeight * ( cache.displayHeight / cache.contentHeight ) + .5 )\
8004\
8005 self:cacheScrollbarPosition()\
8006end\
8007\
8008function ScrollContainer:cacheScrollbarPosition()\
8009 local cache = self.cache\
8010 cache.xScrollPosition, cache.yScrollPosition = math.ceil( self.xScroll / cache.contentWidth * cache.displayWidth + .5 ), math.ceil( self.yScroll / cache.contentHeight * cache.displayHeight + .5 )\
8011\
8012 self.changed = true\
8013 self:redrawArea( 1, 1, self.width, self.height )\
8014end\
8015\
8016configureConstructor {\
8017 argumentTypes = {\
8018 scrollbarColour = \"colour\",\
8019 activeScrollbarColour = \"colour\",\
8020 xScrollAllowed = \"boolean\",\
8021 yScrollAllowed = \"boolean\"\
8022 }\
8023}\
8024",
8025["Node.ti"]="--[[\
8026 A Node is an object which makes up the applications graphical user interface (GUI).\
8027\
8028 Objects such as labels, buttons and text inputs are nodes.\
8029--]]\
8030\
8031class \"Node\" abstract() extends \"Component\" mixin \"MThemeable\" mixin \"MCallbackManager\" {\
8032 static = {\
8033 eventMatrix = {\
8034 mouse_click = \"onMouseClick\",\
8035 mouse_drag = \"onMouseDrag\",\
8036 mouse_up = \"onMouseUp\",\
8037 mouse_scroll = \"onMouseScroll\",\
8038\
8039 key = \"onKeyDown\",\
8040 key_up = \"onKeyUp\",\
8041 char = \"onChar\"\
8042 },\
8043 anyMatrix = {\
8044 MOUSE = \"onMouse\",\
8045 KEY = \"onKey\"\
8046 }\
8047 };\
8048\
8049 disabledColour = 128;\
8050 disabledBackgroundColour = 256;\
8051\
8052 allowMouse = false;\
8053 allowKey = false;\
8054 allowChar = false;\
8055 useAnyCallbacks = false;\
8056\
8057 enabled = true;\
8058 parentEnabled = true;\
8059\
8060 visible = true;\
8061\
8062 needsRedraw = true;\
8063 parent = false;\
8064}\
8065\
8066--[[\
8067 @constructor\
8068 @desc Creates a NodeCanvas (bound to self) and stores it inside of `self.canvas`. This canvas is drawn to the parents canvas at draw time.\
8069]]\
8070function Node:__init__()\
8071 self:register( \"X\", \"Y\", \"colour\", \"backgroundColour\", \"enabled\", \"visible\", \"disabledColour\", \"disabledBackgroundColour\" )\
8072\
8073 if not self.canvas then self.raw.canvas = NodeCanvas( self ) end\
8074end\
8075\
8076--[[\
8077 @constructor\
8078 @desc Finishes construction by hooking the theme manager into the node.\
8079]]\
8080function Node:__postInit__()\
8081 self:hook()\
8082end\
8083\
8084function Node:setParentEnabled( enabled )\
8085 self.parentEnabled = enabled\
8086 self.changed = true\
8087end\
8088\
8089function Node:setNeedsRedraw( needsRedraw )\
8090 self.needsRedraw = needsRedraw\
8091\
8092 if needsRedraw and self.parent then self.parent.needsRedraw = needsRedraw end\
8093end\
8094\
8095--[[\
8096 @instance\
8097 @desc Sets the enabled property of the node to 'enabled'. Sets node's 'changed' to true.\
8098 @param <boolean - enabled>\
8099]]\
8100function Node:setEnabled( enabled )\
8101 self.enabled = enabled\
8102 self.changed = true\
8103end\
8104\
8105--[[\
8106 TODO\
8107]]\
8108function Node:getEnabled()\
8109 if not self.parentEnabled then\
8110 return false\
8111 end\
8112\
8113 return self.enabled\
8114end\
8115\
8116--[[\
8117 TODO\
8118]]\
8119function Node:setParent( parent )\
8120 self.parent = parent\
8121 self.changed = true\
8122\
8123 if parent then\
8124 self.parentEnabled = Titanium.typeOf( parent, \"Application\" ) or parent.enabled\
8125 end\
8126end\
8127\
8128--[[\
8129 @instance\
8130 @desc Sets the node to visible/invisible depending on 'visible' paramater\
8131 @param <boolean - visible>\
8132]]\
8133function Node:setVisible( visible )\
8134 self.visible = visible\
8135 self.changed = true\
8136 if not visible then\
8137 self:queueAreaReset()\
8138 end\
8139end\
8140\
8141--[[\
8142 @instance\
8143 @desc Sets the changed state of this node to 'changed'. If 'changed' then the parents of this node will also have changed set to true.\
8144 @param <boolean - changed>\
8145]]\
8146function Node:setChanged( changed )\
8147 self.changed = changed\
8148\
8149 if changed then\
8150 local parent = self.parent\
8151 if parent and not parent.changed then\
8152 parent.changed = true\
8153 end\
8154\
8155 self.needsRedraw = true\
8156 end\
8157end\
8158\
8159--[[\
8160 @instance\
8161 @desc Handles events by triggering methods on the node depending on the event object passed\
8162 @param <Event Instance* - eventObj>\
8163 @return <boolean - propagate>\
8164\
8165 *Note: The event instance passed can be of variable type, ideally it extends 'Event' so that required methods are implemented on the eventObj.\
8166]]\
8167function Node:handle( eventObj )\
8168 if not self.enabled then return false end\
8169\
8170 local main, sub, within = eventObj.main, eventObj.sub, false\
8171 local handled = eventObj.handled\
8172\
8173 if main == \"MOUSE\" then\
8174 if self.allowMouse then\
8175 within = eventObj.isWithin and eventObj:withinParent( self ) or false\
8176 else return end\
8177 elseif ( main == \"KEY\" and not self.allowKey ) or ( main == \"CHAR\" and not self.allowChar ) then\
8178 return\
8179 end\
8180\
8181 local fn = Node.eventMatrix[ eventObj.name ] or \"onEvent\"\
8182 if self:can( fn ) then\
8183 self[ fn ]( self, eventObj, handled, within )\
8184 end\
8185\
8186 if self.useAnyCallbacks then\
8187 local anyFn = Node.anyMatrix[ main ]\
8188 if self:can( anyFn ) then\
8189 self[ anyFn ]( self, eventObj, handled, within )\
8190 end\
8191 end\
8192\
8193 return true\
8194end\
8195\
8196--[[\
8197 @instance\
8198 @desc Returns the absolute X, Y position of a node rather than its position relative to it's parent.\
8199 @return <number - X>, <number - Y>\
8200]]\
8201function Node:getAbsolutePosition()\
8202 local parent, application = self.parent, self.application\
8203 if parent then\
8204 if parent == application then\
8205 return -1 + application.X + self.X, -1 + application.Y + self.Y\
8206 end\
8207\
8208 local pX, pY = self.parent:getAbsolutePosition()\
8209 return -1 + pX + self.X, -1 + pY + self.Y\
8210 else return self.X, self.Y end\
8211end\
8212\
8213function Node:animate( ... )\
8214 if not self.application then return end\
8215\
8216 return self.application:addAnimation( Tween( self, ... ) )\
8217end\
8218\
8219configureConstructor {\
8220 argumentTypes = { enabled = \"boolean\", visible = \"boolean\", disabledColour = \"colour\", disabledBackgroundColour = \"colour\" }\
8221}\
8222",
8223["NodeCanvas.ti"]="--[[\
8224 The NodeCanvas is an object that allows classes to draw to their canvas using functions that are useful when drawing 'nodes', hence the name.\
8225\
8226 The NodeCanvas is most suited to these use cases:\
8227 - You would like to utilise helpful functions that making drawing nodes easier.\
8228 - Your object is not high level. High level objects use to TermCanvas which draws to the terminal, the NodeCanvas draws to a parent canvas\
8229--]]\
8230\
8231local string_sub = string.sub\
8232\
8233class \"NodeCanvas\" extends \"Canvas\"\
8234\
8235function NodeCanvas:drawPoint( x, y, char, tc, bg )\
8236 if #char > 1 then return error \"drawPoint can only draw one character\" end\
8237\
8238 self.buffer[ ( self.width * ( y - 1 ) ) + x ] = { char, tc or self.colour, bg or self.backgroundColour }\
8239end\
8240\
8241function NodeCanvas:drawTextLine( x, y, text, tc, bg )\
8242 local tc, bg = tc or self.colour, bg or self.backgroundColour\
8243\
8244 local buffer, start = self.buffer, ( self.width * ( y - 1 ) ) + x\
8245 for i = 1, #text do\
8246 buffer[ -1 + start + i ] = { string_sub( text, i, i ), tc, bg }\
8247 end\
8248end\
8249\
8250function NodeCanvas:drawBox( x, y, width, height, col )\
8251 local tc, bg = self.colour, col or self.backgroundColour\
8252 local buffer = self.buffer\
8253\
8254 local px = { \" \", tc, bg }\
8255 for y = math.max( 0, y ), y + height - 1 do\
8256 for x = math.max( 1, x ), x + width - 1 do\
8257 buffer[ ( self.width * ( y - 1 ) ) + x ] = px\
8258 end\
8259 end\
8260end\
8261",
8262["Label.ti"]="--[[\
8263 A Label is a node which displays a single line of text. The text cannot be changed by the user directly, however the text can be changed by the program.\
8264--]]\
8265\
8266class \"Label\" extends \"Node\" {\
8267 labelFor = false;\
8268\
8269 allowMouse = true;\
8270 active = false;\
8271}\
8272\
8273--[[\
8274 @constructor\
8275 @param <string - text>, [number - X], [number - Y]\
8276]]\
8277function Label:__init__( ... )\
8278 self:resolve( ... )\
8279 self.raw.width = #self.text\
8280\
8281 self:super()\
8282 self:register \"text\"\
8283end\
8284\
8285--[[\
8286 @instance\
8287 @desc Mouse click event handler. On click the label will wait for a mouse up, if found labelFor is notified\
8288 @param <MouseEvent Instance - event>, <boolean - handled>, <boolean - within>\
8289]]\
8290function Label:onMouseClick( event, handled, within )\
8291 self.active = self.labelFor and within and not handled\
8292end\
8293\
8294--[[\
8295 @instance\
8296 @desc If the mouse click handler has set the label to active, trigger the onLabelClicked callback\
8297 @param <MouseEvent Instance - event>, <boolean - handled>, <boolean - within>\
8298]]\
8299function Label:onMouseUp( event, handled, within )\
8300 if not self.labelFor then return end\
8301\
8302 local labelFor = self.application:getNode( self.labelFor, true )\
8303 if self.active and not handled and within and labelFor:can \"onLabelClicked\" then\
8304 labelFor:onLabelClicked( self, event, handled, within )\
8305 end\
8306\
8307 self.active = false\
8308end\
8309\
8310--[[\
8311 @instance\
8312 @desc Clears the Label's canvas and draws a line of text if the label has changed.\
8313 @param [boolean - force]\
8314]]\
8315function Label:draw( force )\
8316 local raw = self.raw\
8317 if raw.changed or force then\
8318 raw.canvas:drawTextLine( 1, 1, raw.text )\
8319\
8320 raw.changed = false\
8321 end\
8322end\
8323\
8324--[[\
8325 @instance\
8326 @desc Sets the text of a node. Once set, the nodes 'changed' status is set to true along with its parent(s)\
8327 @param <string - text>\
8328]]\
8329function Label:setText( text )\
8330 if self.text == text then return end\
8331\
8332 self.text = text\
8333 self.width = #text\
8334end\
8335\
8336configureConstructor({\
8337 orderedArguments = { \"text\", \"X\", \"Y\" },\
8338 requiredArguments = { \"text\" },\
8339 argumentTypes = { text = \"string\" }\
8340}, true)\
8341",
8342["Application.ti"]="--[[\
8343 An Application object is the entry point to a Titanium Application.\
8344 The program loop, nodes, threads and animations are handled by the Application object.\
8345--]]\
8346\
8347class \"Application\" extends \"Component\" mixin \"MThemeManager\" mixin \"MKeyHandler\" mixin \"MCallbackManager\" mixin \"MAnimationManager\" mixin \"MNodeContainer\" {\
8348 width = 51;\
8349 height = 19;\
8350\
8351 threads = {};\
8352 nodes = {};\
8353\
8354 running = false;\
8355 terminatable = false;\
8356}\
8357\
8358--[[\
8359 @constructor\
8360 @desc Constructs an instance of the Application by setting all necessary unique properties on it\
8361 @param [number - width], [number - height]\
8362 @return <nil>\
8363]]\
8364function Application:__init__( ... )\
8365 self:resolve( ... )\
8366 self.canvas = TermCanvas( self )\
8367\
8368 self:setMetaMethod(\"add\", function( a, b )\
8369 local t = a ~= self and a or b\
8370\
8371 if Titanium.typeOf( t, \"Node\", true ) then\
8372 return self:addNode( t )\
8373 elseif Titanium.typeOf( t, \"Thread\", true ) then\
8374 return self:addThread( t )\
8375 end\
8376\
8377 error \"Invalid targets for application '__add'. Expected node or thread.\"\
8378 end)\
8379end\
8380\
8381function Application:focusNode( node )\
8382 if not Titanium.typeOf( node, \"Node\", true ) then\
8383 return error \"Failed to update application focused node. Invalid node object passed.\"\
8384 end\
8385\
8386 self:unfocusNode()\
8387 self.focusedNode = node\
8388 node.changed = true\
8389\
8390\
8391 node:executeCallbacks( \"focus\", self )\
8392end\
8393\
8394function Application:unfocusNode( targetNode )\
8395 local node = self.focusedNode\
8396 if not node or ( targetNode ~= node ) then return end\
8397\
8398 self.focusedNode = nil\
8399\
8400 node.raw.focused = false\
8401 node.changed = true\
8402\
8403 node:executeCallbacks( \"unfocus\", self )\
8404end\
8405\
8406--[[\
8407 @instance\
8408 @desc Adds a new thread named 'name' running 'func'. This thread will receive events caught by the Application engine\
8409 @param <threadObj - Thread Instance>\
8410 @return [threadObj | error]\
8411]]\
8412function Application:addThread( threadObj )\
8413 if not Titanium.typeOf( threadObj, \"Thread\", true ) then\
8414 error( \"Failed to add thread, object '\"..tostring( threadObj )..\"' is invalid. Thread Instance required\")\
8415 end\
8416\
8417 table.insert( self.threads, threadObj )\
8418\
8419 return threadObj\
8420end\
8421\
8422--[[\
8423 @instance\
8424 @desc Removes the thread named 'name'*\
8425 @param <Instance 'Thread'/string name - target>\
8426 @return <boolean - success>, [node - removedThread**]\
8427\
8428 *Note: In order for the thread to be removed its 'id' field must match the 'id' parameter.\
8429 **Note: Removed thread will only be returned if a thread was removed (and thus success 'true')\
8430]]\
8431function Application:removeThread( target )\
8432 if not Titanium.typeOf( target, \"Thread\", true ) then\
8433 return error( \"Cannot perform search for thread using target '\"..tostring( target )..\"'.\" )\
8434 end\
8435\
8436 local searchID = type( target ) == \"string\"\
8437 local threads, thread, threadID = self.threads\
8438 for i = 1, #threads do\
8439 thread = threads[ i ]\
8440\
8441 if ( searchID and thread.id == target ) or ( not searchID and thread == target ) then\
8442 thread:stop()\
8443\
8444 table.remove( threads, i )\
8445 return true, thread\
8446 end\
8447 end\
8448\
8449 return false\
8450end\
8451\
8452--[[\
8453 @instance\
8454 @desc Ships events to threads, if the thread requires a Titanium event, that will be passed instead.\
8455 @param <AnyEvent - eventObj>, <vararg - eData>\
8456]]\
8457function Application:handleThreads( eventObj, ... )\
8458 local threads = self.threads\
8459\
8460 local thread\
8461 for i = 1, #threads do\
8462 thread = threads[ i ]\
8463\
8464 if thread.titaniumEvents then\
8465 thread:handle( eventObj )\
8466 else\
8467 thread:handle( ... )\
8468 end\
8469 end\
8470end\
8471\
8472--[[\
8473 @instance\
8474 @desc Begins the program loop\
8475]]\
8476function Application:start( preserve )\
8477 if not preserve then\
8478 Titanium.VFS = nil\
8479 end\
8480\
8481 self.running = true\
8482 while self.running do\
8483 self:draw()\
8484 local event = { coroutine.yield() }\
8485 local eName = event[ 1 ]\
8486\
8487 if eName == \"timer\" and event[ 2 ] == self.timer then\
8488 self:updateAnimations()\
8489 elseif eName == \"terminate\" and self.terminatable then\
8490 printError \"Application Terminated\"\
8491 self:stop()\
8492 end\
8493\
8494 self:handle( unpack( event ) )\
8495 end\
8496end\
8497\
8498--[[\
8499 @instance\
8500 @desc Draws changed nodes (or all nodes if 'force' is true)\
8501 @param [boolean - force]\
8502]]\
8503function Application:draw( force )\
8504 if not self.changed and not force then return end\
8505\
8506 if self.needsThemeUpdate then\
8507 self:update()\
8508 self.needsThemeUpdate = false\
8509 end\
8510\
8511 local canvas = self.canvas\
8512 local nodes, node = self.nodes\
8513\
8514 for i = 1, #nodes do\
8515 node = nodes[ i ]\
8516 if node.needsRedraw and node.visible then\
8517 node:draw( force )\
8518\
8519 node.canvas:drawTo( canvas, node.X, node.Y )\
8520 node.needsRedraw = false\
8521 end\
8522 end\
8523 self.changed = false\
8524\
8525 local focusedNode, caretEnabled, caretX, caretY, caretColour = self.focusedNode\
8526 if focusedNode and focusedNode:can \"getCaretInfo\" then\
8527 caretEnabled, caretX, caretY, caretColour = focusedNode:getCaretInfo()\
8528 end\
8529\
8530 term.setCursorBlink( caretEnabled or false )\
8531 canvas:draw( force )\
8532\
8533 if caretEnabled then\
8534 term.setTextColour( caretColour or self.colour or 32768 )\
8535 term.setCursorPos( caretX or 1, caretY or 1 )\
8536 end\
8537end\
8538\
8539--[[\
8540 @instance\
8541 @desc Spawns a Titanium event instance and ships it to nodes and threads.\
8542 @param <table - event>\
8543]]\
8544function Application:handle( eName, ... )\
8545 local eventObject = Event.spawn( eName, ... )\
8546 if eventObject.main == \"KEY\" then self:handleKey( eventObject ) end\
8547\
8548 local nodes, node = self.nodes\
8549 for i = #nodes, 1, -1 do\
8550 node = nodes[ i ]\
8551 -- The node will update itself depending on the event. Once all are updated they are drawn if changed.\
8552 if node then node:handle( eventObject ) end\
8553 end\
8554\
8555 self:executeCallbacks( eName, eventObject )\
8556 self:handleThreads( eventObject, eName, ... )\
8557end\
8558\
8559--[[\
8560 @instance\
8561 @desc Stops the program loop\
8562]]\
8563function Application:stop()\
8564 if self.running then\
8565 self.running = false\
8566 os.queueEvent( \"ti_app_close\" )\
8567 else\
8568 return error \"Application already stopped\"\
8569 end\
8570end\
8571",
8572}
8573local scriptFiles = {
8574["Titanium.lua"]=true,
8575["Class.lua"]=true,
8576}
8577local preLoad = {
8578}
8579local loaded = {}
8580local function loadFile( name, verify )
8581 if loaded[ name ] then return end
8582
8583 local content = files[ name ]
8584 if content then
8585 local output, err = loadstring( content, name )
8586 if not output or err then return error( "Failed to load Lua chunk. File '"..name.."' has a syntax error: "..tostring( err ), 0 ) end
8587
8588 local ok, err = pcall( output )
8589 if not ok or err then return error( "Failed to execute Lua chunk. File '"..name.."' crashed: "..tostring( err ), 0 ) end
8590
8591 if verify then
8592 local className = name:gsub( "%..*", "" )
8593 local class = Titanium.getClass( className )
8594
8595 if class then
8596 if not class:isCompiled() then class:compile() end
8597 else return error( "File '"..name.."' failed to create class '"..className.."'" ) end
8598 end
8599
8600 loaded[ name ] = true
8601 else return error("Failed to load Titanium. File '"..tostring( name ).."' cannot be found.") end
8602end
8603
8604-- Load our class file
8605loadFile( "Class.lua" )
8606
8607Titanium.setClassLoader(function( name )
8608 local fName = name..".ti"
8609
8610 if not files[ fName ] then
8611 return error("Failed to find file '"..fName..", to load missing class '"..name.."'.", 3)
8612 else
8613 loadFile( fName, true )
8614 end
8615end)
8616
8617-- Load any files specified by our config file
8618for i = 1, #preLoad do loadFile( preLoad[ i ], not scriptFiles[ preLoad[ i ] ] ) end
8619
8620-- Load all class files
8621for name in pairs( files ) do if not scriptFiles[ name ] then
8622 loadFile( name, true )
8623end end
8624
8625-- Load all script files
8626for name in pairs( scriptFiles ) do loadFile( name, false ) end
8627
8628IF FILE IS TRUE == FALSE
8629 wait(0.2)
8630 inform2("Original ID: "..forcheck)
8631 elseif smode == 2 then
8632 forcheck=421360692
8633 inform2("Variable: always_lying")
8634 wait(0.2)
8635 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8636 wait(0.2)
8637 inform2("Original ID: "..forcheck)
8638 elseif smode == 3 then
8639 forcheck=142523507
8640 inform2("Variable: jawn")
8641 wait(0.2)
8642 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8643 wait(0.2)
8644 inform2("Original ID: "..forcheck)
8645 end
8646 end
8647 end
8648 end
8649 if key == "T" or key == "t" then
8650 AnimationStop()
8651 haha_no = true
8652 M4:Play()
8653 if advan == false then
8654 if smode == 1 then
8655 inform2("haha_no")
8656 elseif smode == 2 then
8657 inform2("ok_you_re_hearing_some_cancerous_stuff_i_give_up_now")
8658 elseif smode == 3 then
8659 inform2("this_is_epic")
8660 end
8661 if advan == true then
8662 if smode == 1 then
8663 forcheck=258500169
8664 inform2("Variable: haha_no")
8665 wait(0.2)
8666 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8667 wait(0.2)
8668 inform2("Original ID: "..forcheck)
8669 elseif smode == 2 then
8670 forcheck=416308003
8671 inform2("Variable: ok_you_re_hearing_some_cancerous_stuff_i_give_up_now")
8672 wait(0.2)
8673 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8674 wait(0.2)
8675 inform2("Original ID: "..forcheck)
8676 elseif smode == 3 then
8677 forcheck=151021035
8678 inform2("Variable: this_is_epic")
8679 wait(0.2)
8680 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8681 wait(0.2)
8682 inform2("Original ID: "..forcheck)
8683 end
8684 end
8685 end
8686 end
8687 if key == "Y" or key == "y" then
8688 AnimationStop()
8689 spin_round = true
8690 M5:Play()
8691 if advan == false then
8692 if smode == 1 then
8693 inform2("spin_round")
8694 elseif smode == 2 then
8695 inform2("hard_one")
8696 elseif smode == 3 then
8697 inform2("gta_loud")
8698 end
8699 if advan == true then
8700 if smode == 1 then
8701 forcheck=187013797
8702 inform2("Variable: spin_round")
8703 wait(0.2)
8704 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8705 wait(0.2)
8706 inform2("Original ID: "..forcheck)
8707 elseif smode == 2 then
8708 forcheck=462957432
8709 inform2("Variable: hard_one")
8710 wait(0.2)
8711 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8712 wait(0.2)
8713 inform2("Original ID: "..forcheck)
8714 elseif smode == 3 then
8715 forcheck=253539621
8716 inform2("Variable: gta_loud")
8717 wait(0.2)
8718 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8719 wait(0.2)
8720 inform2("Original ID: "..forcheck)
8721 end
8722 end
8723 end
8724 end
8725 if key == "U" or key == "u" then
8726 AnimationStop()
8727 still_not_that_fast = true
8728 M6:Play()
8729 if advan == false then
8730 if smode == 1 then
8731 inform2("still_not_that_fast")
8732 elseif smode == 2 then
8733 inform2("ok")
8734 elseif smode == 3 then
8735 inform2("sanic_x")
8736 end
8737 if advan == true then
8738 if smode == 1 then
8739 forcheck=224705079
8740 inform2("Variable: still_not_that_fast")
8741 wait(0.2)
8742 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8743 wait(0.2)
8744 inform2("Original ID: "..forcheck)
8745 elseif smode == 2 then
8746 forcheck=385741330
8747 inform2("Variable: ok")
8748 wait(0.2)
8749 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8750 wait(0.2)
8751 inform2("Original ID: "..forcheck)
8752 elseif smode == 3 then
8753 forcheck=178752763
8754 inform2("Variable: sanic_x")
8755 wait(0.2)
8756 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8757 wait(0.2)
8758 inform2("Original ID: "..forcheck)
8759 end
8760 end
8761 end
8762 end
8763 if key == "F" or key == "f" then
8764 AnimationStop()
8765 tetris_remix = true
8766 M7:Play()
8767 if barrelbrick == nil and tetris_remix == true then
8768 barrelbrick = P(2,2,1,'Black',0,false,false)
8769 a=fm(barrelbrick,0,0.5,0.5,0.5,0) a.VertexColor = Vector3.new(1,1,1)
8770 We(barrelbrick,char.Torso,0,10,0,90,90,90)
8771 end
8772 if advan == false then
8773 if smode == 1 then
8774 inform2("tetris_remix")
8775 elseif smode == 2 then
8776 inform2("it_s_low")
8777 elseif smode == 3 then
8778 inform2("mlg_dubbs")
8779 end
8780 if advan == true then
8781 if smode == 1 then
8782 forcheck=200624713
8783 inform2("Variable: tetris_remix")
8784 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8785 inform2("Original ID: "..forcheck)
8786 elseif smode == 2 then
8787 forcheck=334046170
8788 inform2("Variable: it_s_low")
8789 wait(0.2)
8790 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8791 wait(0.2)
8792 inform2("Original ID: "..forcheck)
8793 elseif smode == 3 then
8794 forcheck=340617496
8795 inform2("Variable: mlg_dubbs")
8796 wait(0.2)
8797 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8798 wait(0.2)
8799 inform2("Original ID: "..forcheck)
8800 end
8801 end
8802 end
8803 end
8804 if key == "P" or key == "p" then
8805 AnimationStop()
8806 dat_boi = true
8807 M8:Play()
8808 if saxtool == nil and dat_boi == true then
8809 saxtool = P(1,2,2,'Black',0,false,false)
8810 a=fm(saxtool,44410178,1.5,1.5,1.5,44410320) a.VertexColor = Vector3.new(1,1,1)
8811 b=We(saxtool,char:FindFirstChild("Left Arm"),0,-1,0,0,0,0)
8812 b.C1 = CFrame.new(0.5, -0.9, -0.3) * CFrame.Angles(math.pi/1.5, -math.pi/2, -math.pi/8)
8813 end
8814 if advan == false then
8815 if smode == 1 then
8816 inform2("dat_boi")
8817 elseif smode == 2 then
8818 inform2("ayyyyyyyyyyyyyyyyyyyyyyyy_lmao")
8819 elseif smode == 3 then
8820 inform2("_2204355")
8821 end
8822 if advan == true then
8823 if smode == 1 then
8824 forcheck=410806544
8825 inform2("Variable: dat_boi")
8826 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8827 inform2("Original ID: "..forcheck)
8828 elseif smode == 2 then
8829 forcheck=400663465
8830 inform2("Variable: ayyyyyyyyyyyyyyyyyyyyyyyy_lmao")
8831 wait(0.2)
8832 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8833 wait(0.2)
8834 inform2("Original ID: "..forcheck)
8835 elseif smode == 3 then
8836 forcheck=142355221
8837 inform2("Variable: _2204355")
8838 wait(0.2)
8839 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8840 wait(0.2)
8841 inform2("Original ID: "..forcheck)
8842 end
8843 end
8844 end
8845 end
8846 if key == "G" or key == "g" then
8847 AnimationStop()
8848 memes = true
8849 M9:Play()
8850 if advan == false then
8851 if smode == 1 then
8852 inform2("memes")
8853 elseif smode == 2 then
8854 inform2("TGG")
8855 elseif smode == 3 then
8856 inform2("mlg_style")
8857 end
8858 if advan == true then
8859 if smode == 1 then
8860 forcheck=242178814
8861 inform2("Variable: memes")
8862 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8863 inform2("Original ID: "..forcheck)
8864 elseif smode == 2 then
8865 forcheck=297802798
8866 inform2("Variable: TGG")
8867 wait(0.2)
8868 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8869 wait(0.2)
8870 inform2("Original ID: "..forcheck)
8871 elseif smode == 3 then
8872 forcheck=362846090
8873 inform2("Variable: mlg_style")
8874 wait(0.2)
8875 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8876 wait(0.2)
8877 inform2("Original ID: "..forcheck)
8878 end
8879 end
8880 end
8881 end
8882 if key == "H" or key == "h" then
8883 AnimationStop()
8884 scary_monsters_nice_sprites_remix = true
8885 M10:Play()
8886 if advan == false then
8887 if smode == 1 then
8888 inform2("scary_monsters_nice_sprites_remix")
8889 elseif smode == 2 then
8890 inform2("yeah_bass")
8891 elseif smode == 3 then
8892 inform2("paper_mario")
8893 end
8894 if advan == true then
8895 if smode == 1 then
8896 forcheck=142375403
8897 inform2("Variable: scary_monsters_nice_sprites_remix")
8898 wait(0.2)
8899 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8900 wait(0.2)
8901 inform2("Original ID: "..forcheck)
8902 elseif smode == 2 then
8903 forcheck=410005698
8904 inform2("Variable: yeah_bass")
8905 wait(0.2)
8906 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8907 wait(0.2)
8908 inform2("Original ID: "..forcheck)
8909 elseif smode == 3 then
8910 forcheck=145369820
8911 inform2("Variable: paper_mario")
8912 wait(0.2)
8913 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8914 wait(0.2)
8915 inform2("Original ID: "..forcheck)
8916 end
8917 end
8918 end
8919 end
8920 if key == "J" or key == "j" then
8921 AnimationStop()
8922 rus = true
8923 M11:Play()
8924 if advan == false then
8925 if smode == 1 then
8926 inform2("rus")
8927 elseif smode == 2 then
8928 inform2("we_rise")
8929 elseif smode == 3 then
8930 inform2("otis")
8931 end
8932 if advan == true then
8933 if smode == 1 then
8934 forcheck=542441126
8935 inform2("Variable: rus")
8936 wait(0.2)
8937 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8938 wait(0.2)
8939 inform2("Original ID: "..forcheck)
8940 elseif smode == 2 then
8941 forcheck=427801633
8942 inform2("Variable: we_rise")
8943 wait(0.2)
8944 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8945 wait(0.2)
8946 inform2("Original ID: "..forcheck)
8947 elseif smode == 3 then
8948 forcheck=142308159
8949 inform2("Variable: otis")
8950 wait(0.2)
8951 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8952 wait(0.2)
8953 inform2("Original ID: "..forcheck)
8954 end
8955 end
8956 end
8957 end
8958 if key == "K" or key == "k" then
8959 AnimationStop()
8960 it_s_already_that_old = true
8961 M12:Play()
8962 if advan == false then
8963 if smode == 1 then
8964 inform2("it_s_already_that_old")
8965 elseif smode == 2 then
8966 inform2("yeah")
8967 elseif smode == 3 then
8968 inform2("LJN")
8969 end
8970 if advan == true then
8971 if smode == 1 then
8972 forcheck=501548847
8973 inform2("Variable: it_s_already_that_old")
8974 wait(0.2)
8975 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8976 wait(0.2)
8977 inform2("Original ID: "..forcheck)
8978 elseif smode == 2 then
8979 forcheck=277253359
8980 inform2("Variable: yeah")
8981 wait(0.2)
8982 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8983 wait(0.2)
8984 inform2("Original ID: "..forcheck)
8985 elseif smode == 3 then
8986 forcheck=167373003
8987 inform2("Variable: LJN")
8988 wait(0.2)
8989 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
8990 wait(0.2)
8991 inform2("Original ID: "..forcheck)
8992 end
8993 end
8994 end
8995 end
8996 if key == "L" or key == "l" then
8997 AnimationStop()
8998 pootis_avi = true
8999 M13:Play()
9000 if advan == false then
9001 if smode == 1 then
9002 inform2("pootis_avi")
9003 elseif smode == 2 then
9004 inform2("it_s_metal")
9005 elseif smode == 3 then
9006 inform2("ITS_NO_USE")
9007 end
9008 if advan == true then
9009 if smode == 1 then
9010 forcheck=336581561
9011 inform2("Variable: pootis_avi")
9012 wait(0.2)
9013 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9014 wait(0.2)
9015 inform2("Original ID: "..forcheck)
9016 elseif smode == 2 then
9017 forcheck=184740384
9018 inform2("Variable: it_s_metal")
9019 wait(0.2)
9020 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9021 wait(0.2)
9022 inform2("Original ID: "..forcheck)
9023 elseif smode == 3 then
9024 forcheck=130844716
9025 inform2("Variable: ITS_NO_USE")
9026 wait(0.2)
9027 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9028 wait(0.2)
9029 inform2("Original ID: "..forcheck)
9030 end
9031 end
9032 end
9033 end
9034 if key == "Z" or key == "z" then
9035 AnimationStop()
9036 buelah_mp3 = true
9037 M14:Play()
9038 if advan == false then
9039 if smode == 1 then
9040 inform2("buelah_mp3")
9041 elseif smode == 2 then
9042 inform2("GOOD_JOB")
9043 elseif smode == 3 then
9044 inform2("spm")
9045 end
9046 if advan == true then
9047 if smode == 1 then
9048 forcheck=214285554
9049 inform2("Variable: buelah_mp3")
9050 wait(0.2)
9051 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9052 wait(0.2)
9053 inform2("Original ID: "..forcheck)
9054 elseif smode == 2 then
9055 forcheck=225074231
9056 inform2("Variable: GOOD_JOB")
9057 wait(0.2)
9058 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9059 wait(0.2)
9060 inform2("Original ID: "..forcheck)
9061 elseif smode == 3 then
9062 forcheck=202234516
9063 inform2("Variable: spm")
9064 wait(0.2)
9065 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9066 wait(0.2)
9067 inform2("Original ID: "..forcheck)
9068 end
9069 end
9070 end
9071 end
9072 if key == "X" or key == "x" then
9073 AnimationStop()
9074 antivirisis = true
9075 M15:Play()
9076 if sandstorm == nil and antivirisis == true then
9077 sandstorm = P(1,1,1,'Black',0,false,false)
9078 sandstorm.Transparency = 1
9079 a=Instance.new("Smoke",sandstorm)
9080 a.Color = Color3.new(255/255,255/255,175/255)
9081 a.Size = 0.4
9082 a.RiseVelocity = 3
9083 a.Opacity = 0.75
9084 b=We(sandstorm,char:FindFirstChild("Torso"),0,0,0,0,0,0)
9085 b.C1 = CFrame.new(0, -2, 0)
9086 end
9087 if advan == false then
9088 if smode == 1 then
9089 inform2("antivirisis")
9090 elseif smode == 2 then
9091 inform2("hardness")
9092 elseif smode == 3 then
9093 inform2("stylo")
9094 end
9095 if advan == true then
9096 if smode == 1 then
9097 forcheck=278068026
9098 inform2("Variable: antivirisis")
9099 wait(0.2)
9100 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9101 wait(0.2)
9102 inform2("Original ID: "..forcheck)
9103 elseif smode == 2 then
9104 forcheck=265479911
9105 inform2("Variable: hardness")
9106 wait(0.2)
9107 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9108 wait(0.2)
9109 inform2("Original ID: "..forcheck)
9110 elseif smode == 3 then
9111 forcheck=144940679
9112 inform2("Variable: stylo")
9113 wait(0.2)
9114 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9115 wait(0.2)
9116 inform2("Original ID: "..forcheck)
9117 end
9118 end
9119 end
9120 end
9121 if key == "C" or key == "c" then
9122 AnimationStop()
9123 look_at_this_dude = true
9124 M16:Play()
9125 if advan == false then
9126 if smode == 1 then
9127 inform2("look_at_this_dude")
9128 elseif smode == 2 then
9129 inform2("hard_bass")
9130 elseif smode == 3 then
9131 inform2("nedm")
9132 end
9133 if advan == true then
9134 if smode == 1 then
9135 forcheck=424610918
9136 inform2("Variable: look_at_this_dude")
9137 wait(0.2)
9138 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9139 wait(0.2)
9140 inform2("Original ID: "..forcheck)
9141 elseif smode == 2 then
9142 forcheck=324499479
9143 inform2("Variable: hard_bass")
9144 wait(0.2)
9145 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9146 wait(0.2)
9147 inform2("Original ID: "..forcheck)
9148 elseif smode == 3 then
9149 forcheck=138811227
9150 inform2("Variable: nedm")
9151 wait(0.2)
9152 inform2("Original name: "..game:GetService("MarketplaceService"):GetProductInfo(forcheck,Enum.InfoType.Asset).Name)
9153 wait(0.2)
9154 inform2("Original ID: "..forcheck)
9155 end
9156 end
9157 end
9158 end
9159 if key == "V" or key == "v" then
9160 smode = 1
9161 M1.SoundId=Asset.."482893067"
9162 M2.SoundId=Asset.."408731259"
9163 M3.SoundId=Asset.."257341751"
9164 M4.SoundId=Asset.."258500169"
9165 M5.SoundId=Asset.."187013797"
9166 M6.SoundId=Asset.."224705079"
9167 M7.SoundId=Asset.."200624713"
9168 M8.SoundId=Asset.."410806544"
9169 M9.SoundId=Asset.."242178814"
9170 M10.SoundId=Asset.."142375403"
9171 M11.SoundId=Asset.."542441126"
9172 M12.SoundId=Asset.."501548847"
9173 M13.SoundId=Asset.."336581561"
9174 M14.SoundId=Asset.."214285554"
9175 M15.SoundId=Asset.."278068026"
9176 M16.SoundId=Asset.."424610918"
9177 inform2("Smode: 1 (Original Music)")
9178 end
9179 if key == "B" or key == "b" then
9180 smode = 2
9181 M1.SoundId=Asset.."561274893"
9182 M2.SoundId=Asset.."273029844"
9183 M3.SoundId=Asset.."421360692"
9184 M4.SoundId=Asset.."416308003"
9185 M5.SoundId=Asset.."462957432"
9186 M6.SoundId=Asset.."385741330"
9187 M7.SoundId=Asset.."334046170"
9188 M8.SoundId=Asset.."400663465"
9189 M9.SoundId=Asset.."297802798"
9190 M10.SoundId=Asset.."410005698"
9191 M11.SoundId=Asset.."427801633"
9192 M12.SoundId=Asset.."277253359"
9193 M13.SoundId=Asset.."184740384"
9194 M14.SoundId=Asset.."225074231"
9195 M15.SoundId=Asset.."265479911"
9196 M16.SoundId=Asset.."324499479"
9197 inform2("Smode: 2 (Other Music)")
9198 end
9199 if key == "N" or key == "n" then
9200 smode = 3
9201 M1.SoundId=Asset.."168340433"
9202 M2.SoundId=Asset.."265576262"
9203 M3.SoundId=Asset.."142523507"
9204 M4.SoundId=Asset.."151021035"
9205 M5.SoundId=Asset.."253539621"
9206 M6.SoundId=Asset.."178752763"
9207 M7.SoundId=Asset.."340617496"
9208 M8.SoundId=Asset.."142355221"
9209 M9.SoundId=Asset.."362846090"
9210 M10.SoundId=Asset.."145369820"
9211 M11.SoundId=Asset.."142308159"
9212 M12.SoundId=Asset.."167373003"
9213 M13.SoundId=Asset.."130844716"
9214 M14.SoundId=Asset.."202234516"
9215 M15.SoundId=Asset.."144940679"
9216 M16.SoundId=Asset.."138811227"
9217 inform2("Smode: 3 (Music From the 1st Edit)")
9218 end
9219 if key == "M" or key == "m" then
9220 if advan == false then
9221 advan = true
9222 inform2("Advanced details are on")
9223 elseif advan == true then
9224 advan = false
9225 inform2("Advanced details are off")
9226 end
9227 end
9228 end
9229 end
9230 end
9231end
9232
9233Generate(Player)
9234
9235game:service'RunService'.Stepped:connect(function()
9236 count = (count % 100) + countspeed
9237 angle = math.pi * math.sin(math.pi*2/100*count)
9238 countspeed = 1
9239
9240 state = humanoid:GetState()
9241 if state ~= Enum.HumanoidStateType.Freefall then
9242 jump = false
9243 else
9244 jump = true
9245 sit = false
9246 AnimationStop()
9247 end
9248
9249 local mesh1anan = Instance.new("SpecialMesh")
9250 mesh1anan.MeshType = Enum.MeshType.FileMesh
9251 mesh1anan.Scale = Vector3.new(1,1,1)
9252 mesh1anan.MeshId = "rbxassetid://431000837"
9253 mesh1anan.TextureId = "rbxassetid://431000842"
9254 if look_at_this_dude == true then
9255 if char ~= nil then
9256 local locationanan = char:GetModelCFrame()
9257 local tacoa = Instance.new("Part")
9258 tacoa.CanCollide = false
9259 tacoa.RotVelocity = Vector3.new(math.random()*math.pi,math.random()*math.pi,math.random()*math.pi)
9260 local meshanananan = mesh1anan:clone()
9261 meshanananan.Parent = tacoa
9262 meshanananan.Scale = Vector3.new(1,1,1)
9263 tacoa.CFrame = locationanan * CFrame.new(math.random()*500 - 250,math.random(100,200),math.random()*500 - 250)
9264 tacoa.Parent = workspace
9265 game:GetService("Debris"):AddItem(tacoa,4)
9266 end
9267 end
9268
9269
9270
9271
9272 if some_power == false then
9273 M1:Stop()
9274 end
9275 if _2_much_power == false then
9276 M2:Stop()
9277 end
9278 if unity == false then
9279 M3:Stop()
9280 end
9281 if haha_no == false then
9282 M4:Stop()
9283 end
9284 if spin_round == false then
9285 M5:Stop()
9286 end
9287 if still_not_that_fast == false then
9288 M6:Stop()
9289 end
9290 if tetris_remix == false then
9291 M7:Stop()
9292 end
9293 if dat_boi == false then
9294 M8:Stop()
9295 end
9296 if memes == false then
9297 M9:Stop()
9298 end
9299 if scary_monsters_nice_sprites_remix == false then
9300 M10:Stop()
9301 end
9302 if rus == false then
9303 M11:Stop()
9304 end
9305 if it_s_already_that_old == false then
9306 M12:Stop()
9307 end
9308 if pootis_avi == false then
9309 M13:Stop()
9310 end
9311 if buelah_mp3 == false then
9312 M14:Stop()
9313 end
9314 if antivirisis == false then
9315 M15:Stop()
9316 end
9317 if look_at_this_dude == false then
9318 M16:Stop()
9319 end
9320
9321 if run == true and sit == false then
9322 humanoid.WalkSpeed = 25
9323 elseif sit == true then
9324 humanoid.WalkSpeed = 0
9325 else
9326 humanoid.WalkSpeed = 16
9327 end
9328
9329 if global_wait == 380 then global_wait = 0 end
9330
9331 if (W == false or A == false or S == false or D == false) and jump == false and sit == false then
9332 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/75)
9333 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/75)
9334 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/75)
9335 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/75)
9336 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/75, math.pi, 0)
9337 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9338 end
9339
9340
9341 if (W == false or A == false or S == false or D == false) and jump == false and sit == true then
9342 local ray = Ray.new(torso.Position, Vector3.new(0, -3, 0))
9343 local hitz,enz = workspace:FindPartOnRay(ray, char)
9344 if hitz then
9345 if rootpart:FindFirstChild("Weld") == nil then
9346 miniweld = Instance.new("Weld", rootpart)
9347 miniweld.C0 = hitz.CFrame:toObjectSpace(rootpart.CFrame)
9348 miniweld.Part0 = hitz
9349 miniweld.Part1 = rootpart
9350 humanoid.PlatformStand = true
9351 end
9352 end
9353 else
9354 if rootpart:FindFirstChild("Weld") ~= nil then
9355 rootpart:FindFirstChild("Weld"):Destroy()
9356 humanoid.PlatformStand = false
9357 end
9358 end
9359
9360 if (W == false or A == false or S == false or D == false) and jump == false and sit == true then
9361 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - math.pi/15)
9362 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 + math.pi/15)
9363 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + math.pi/8, 0, math.pi/2 - math.pi/15)
9364 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + math.pi/8, 0, -math.pi/2 + math.pi/15)
9365 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + math.pi/15, math.pi, 0)
9366 rj.C0 = CFrame.new(0, -2, 0) * CFrame.Angles(math.pi/2 + math.pi/15, math.pi, 0)
9367 end
9368
9369 if jump == true and sit == false then
9370 countspeed = 2
9371 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi + angle/12)
9372 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi + angle/12)
9373 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/12)
9374 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/12)
9375 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/25, math.pi, 0)
9376 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2+ angle/50, math.pi, 0)
9377 end
9378
9379 if (W == true or A == true or S == true or D == true) and jump == false and sit == false then
9380 if run == true then
9381 countspeed = 4
9382 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/3)
9383 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/3)
9384 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/5)
9385 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/5)
9386 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/20, math.pi, 0)
9387 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2 + angle/40, math.pi, 0)
9388 else
9389 countspeed = 2
9390 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/4)
9391 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 - angle/4)
9392 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/6)
9393 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/6)
9394 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/25, math.pi, 0)
9395 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2+ angle/50, math.pi, 0)
9396 end
9397 end
9398
9399 if W == false and A == false and S == false and D == false and jump == false and sit == false then
9400 if unity == true and jump == false and sit == false then
9401 countspeed = 2
9402 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(angle/5, 0, angle/4)
9403 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(angle/5, 0, -angle/4)
9404 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(angle/10, 0, angle/5)-- * CFrame.Angles(angle*0.5, 0, -math.abs(angle*0.15))
9405 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(angle/10, 0, angle/5)-- * CFrame.Angles(-angle*0.5, 0, math.abs(angle*0.15))
9406 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/5, math.pi, 0)
9407 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2 + angle/5, math.pi, 0)
9408 elseif _2_much_power == true and jump == false and sit == false then
9409 countspeed = 4
9410 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(angle/15, 0, angle/15)
9411 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(angle/15, 0, angle/15)
9412 ls.C1 = CFrame.new(0.25,0.5 + 1 * angle/10,0.5) * CFrame.Angles(math.pi + angle/10, 0, 0 + angle/10)
9413 rs.C1 = CFrame.new(-0.25,0.5 + 1 * angle/10,0.5) * CFrame.Angles(math.pi + angle/10, 0, 0 + angle/10)
9414 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/10, math.pi, 0)
9415 rj.C0 = CFrame.new(0, 0.5 + angle/5, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9416 elseif some_power == true and jump == false and sit == false then
9417 countspeed = 2
9418 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0 + angle/8, 0, math.pi/12 + angle/12)
9419 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0 + angle/8, 0, -math.pi/12 - angle/12)
9420 lh.C1 = CFrame.new(0.35,0.7,0.5) * CFrame.Angles(0 + angle/10, 0, -math.pi/8)
9421 rh.C1 = CFrame.new(-0.35,0.7,0.5) * CFrame.Angles(0 + angle/10, 0, math.pi/8)
9422 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/15, math.pi, 0)
9423 rj.C0 = CFrame.new(angle/4, -0.3 + angle/20, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9424 elseif haha_no == true and jump == false and sit == false then
9425 countspeed = 4
9426 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(math.pi/4, math.pi/8 + angle/8, math.pi/4 + angle/8)
9427 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(math.pi/4, -math.pi/8 + angle/8, -math.pi/4 + angle/8)
9428 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/10, 0, 0 + angle/10)
9429 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/10, 0, 0 + angle/10)
9430 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/15, math.pi + angle/15, 0 + angle/15)
9431 rj.C0 = CFrame.new(0, 0 + angle/20, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9432 elseif spin_round == true and jump == false and sit == false then
9433 global_wait = (global_wait % 360) + 4
9434 countspeed = 4
9435 ls.C1 = CFrame.new(0,1,0) * CFrame.Angles(math.pi/2, 0 + angle/10, 0 + angle/10)
9436 rs.C1 = CFrame.new(0,1,0) * CFrame.Angles(math.pi/2, 0 - angle/10, 0 + angle/10)
9437 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/10, 0 + angle/10, 0 + angle/10)
9438 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/10, 0 + angle/10, 0 + angle/10)
9439 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9440 rj.C0 = CFrame.new(0 + angle/25, 0, 0 - angle/25) * CFrame.Angles(math.pi/2, math.pi, math.rad(global_wait*4))
9441 elseif still_not_that_fast == true and jump == false and sit == false then
9442 countspeed = 2
9443 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi/2 + angle/15)
9444 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, -math.pi/2 + angle/15)
9445 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(math.pi/60 - angle/45, 0, 0 + angle/15)
9446 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(math.pi/60 + angle/45, 0, 0 + angle/15)
9447 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/15, math.pi + angle/10, 0)
9448 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2 + angle/50 , math.pi + angle/50, 0 + angle/50)
9449 elseif tetris_remix == true and jump == false and sit == false then
9450 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi)
9451 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi)
9452 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0)
9453 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0)
9454 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9455 rj.C0 = CFrame.new(0 + angle, -1.8, 0) * CFrame.Angles(0, math.pi, 0 + angle)
9456 elseif dat_boi == true and jump == false and sit == false then
9457 countspeed = 2
9458 ls.C1 = CFrame.new(0,0.75,-0.25) * CFrame.Angles(-math.pi/5, 0, math.pi/2 - math.abs(angle/30))
9459 rs.C1 = CFrame.new(0,0.75,-0.25) * CFrame.Angles(-math.pi/5, 0, -math.pi/2 + math.abs(angle/30))
9460 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 - math.abs(angle/30))
9461 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + math.abs(angle/30))
9462 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9463 rj.C0 = CFrame.new(0, -math.abs(angle*0.05), math.abs(angle*0.025)) * CFrame.Angles(math.pi/2 + math.abs(angle/20), math.pi, 0)
9464 elseif memes == true and jump == false and sit == false then
9465 countspeed = 3
9466 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi/2 - angle/1.5)
9467 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, -math.pi/2 + angle/1.5)
9468 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 - angle/16)
9469 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 + angle/16)
9470 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/12, math.pi, 0)
9471 rj.C0 = CFrame.new(0, 0 + angle / 35, 0) * CFrame.Angles(math.pi/2 + angle/25, math.pi, 0)
9472 elseif scary_monsters_nice_sprites_remix == true and jump == false and sit == false then
9473 countspeed = 2.5
9474 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(angle/16, angle/16,math.pi/3.5 + angle/8)
9475 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(angle/16, -angle/16,-math.pi/1.5 + -angle/8)
9476 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, angle/16, angle/16)
9477 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, angle/16, angle/16)
9478 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9479 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2-angle/16, math.pi, 0)
9480 elseif rus == true and jump == false and sit == false then
9481 countspeed = 2
9482 ls.C1 = CFrame.new(0,0.75,-0.35) * CFrame.Angles(math.pi/8, 0, math.pi/2 + angle/3.5)
9483 rs.C1 = CFrame.new(0,0.75,-0.35) * CFrame.Angles(math.pi/8, 0, -math.pi/2 + angle/3.5)
9484 lh.C1 = CFrame.new(0 + angle/50,1,0.5) * CFrame.Angles(0, 0 + angle/35, 0 + angle/15)
9485 rh.C1 = CFrame.new(0 + angle/50,1,0.5) * CFrame.Angles(0, 0 + angle/35, 0 + angle/15)
9486 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/15, math.pi, 0)
9487 rj.C0 = CFrame.new(0, 0, 0) * CFrame.Angles(math.pi/2 - angle/35, math.pi - angle/35, 0)
9488 elseif it_s_already_that_old == true and jump == false and sit == false then
9489 countspeed = 4
9490 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, math.pi/2+angle/2)
9491 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, -math.pi/2+angle/2)
9492 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0+angle/32, 0, 0+angle/32)
9493 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0+angle/32, 0, 0-angle/32)
9494 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9495 rj.C0 = CFrame.new(0, 0 - angle/50, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9496 elseif pootis_avi == true and jump == false and sit == false then
9497 countspeed = 4
9498 ls.C1 = CFrame.new(0,0.75,-0.15) * CFrame.Angles(-math.pi/4, 0, (math.pi/2 + angle/14) - math.pi/20)
9499 rs.C1 = CFrame.new(0,0.75,-0.15) * CFrame.Angles(-math.pi/4, 0, (-math.pi/2 - angle/14) + math.pi/20)
9500 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/16, 0, 0)
9501 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0 + angle/16, 0, 0)
9502 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 + angle/20, math.pi, 0)
9503 rj.C0 = CFrame.new(0, 0 + angle/40, 0) * CFrame.Angles(math.pi/2, math.pi, 0)
9504 elseif buelah_mp3 == true and jump == false and sit == false then
9505 countspeed = 2
9506 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(math.pi/12, 0, math.pi/4 + angle/4)
9507 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(math.pi/12, 0, -math.pi/4 + angle/4)
9508 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(math.pi/24, 0, 0 + angle/4)
9509 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(math.pi/24, 0, 0 + angle/4)
9510 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 - angle/8, math.pi, 0)
9511 rj.C0 = CFrame.new(0, 0 + angle/48, 0) * CFrame.Angles(math.pi/2 + angle/24, math.pi, 0)
9512 elseif antivirisis == true and jump == false and sit == false then
9513 countspeed = 3
9514 ls.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 + angle/1.5)
9515 rs.C1 = CFrame.new(0,0.5,-0.5) * CFrame.Angles(0, 0, 0 + angle/3)
9516 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 - angle/3)
9517 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, 0 - angle/1.5)
9518 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2, math.pi, 0)
9519 rj.C0 = CFrame.new(0, 0+ angle/45, 0) * CFrame.Angles(math.pi/2 - angle/6, math.pi, 0)
9520 elseif look_at_this_dude == true and jump == false and sit == false then
9521 countspeed = 4
9522 global_wait = (global_wait % 360) + 4
9523 ls.C1 = CFrame.new(0,1,-0.25) * CFrame.Angles(math.pi/6 + angle/12, 0, math.pi)
9524 rs.C1 = CFrame.new(0,1,-0.25) * CFrame.Angles(math.pi/6 + angle/12, 0, math.pi)
9525 lh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, math.pi/8 + angle/16)
9526 rh.C1 = CFrame.new(0,1,0.5) * CFrame.Angles(0, 0, math.pi/8 + angle/16)
9527 neck.C1 = CFrame.new(0,-0.5,0) * CFrame.Angles(math.pi/2 - math.pi/8 + angle/16, math.pi, 0)
9528 rj.C0 = CFrame.new(0, 0.25 + angle/12, 0) * CFrame.Angles(math.pi/2, math.pi, math.rad(global_wait*4))
9529 end
9530 end
9531end)
9532wait(0.2)
9533inform2(_VERSION.." is cool!!!")
9534
9535while true do
9536wait(2)
9537WorkPlayer.FalseHead.NametagGUI.ImageLabel.TextLabel.TextColor3 = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
9538end
9539
9540while true do
9541 CanCraft = 1
9542 for slot = 1, 4 do
9543 turtle.select(slot)
9544 if turtle.getItemCount(slot) < 1 then
9545 CanCraft = 0
9546 end
9547 end
9548 if CanCraft then
9549 turtle.select(1)
9550 turtle.drop(2)
9551 for slot = 2, 4 do
9552 turtle.select(slot)
9553 turtle.drop(1)
9554 end
9555 end
9556os.sleep(2)
9557end
9558
9559function hasPermission(username,permission)
9560 outputDebugString("Username = "..username.." permission = "..permission)
9561 if username and tostring(permission) then
9562 local currentPerms = getPlayerPermissions(username)
9563 outputDebugString("Current perms of "..username.."are "..currentPerms)
9564 local permissionTable = split(currentPerms, ";") or {currentPerms}
9565 for _,v in pairs(permissionTable) do
9566 if v == permission then
9567 outputDebugString("User has permission, "..permission)
9568 return true
9569 else
9570 outputDebugString("User does not have permission")
9571 return false
9572 end
9573 end
9574 else
9575 outputDebugString("BG_Permissions: Function(hasPermission) Wrong Syntax wariables not passed (Player,Permission) or Player does not exist in database")
9576 return false
9577 end
9578end
9579
9580RegisterNetEvent("cuffPlayer")
9581AddEventHandler('cuffPlayer', function(cop, sus, toggle)
9582 local copp = GetPlayerFromServerId(cop)
9583 local susp = GetPlayerFromServerId(sus)
9584 local copped = GetPlayerPed(copp)
9585 local susped = GetPlayerPed(susp)
9586
9587 if DoesEntityExist(copped) and DoesEntityExist(susped) and not IsEntityDead(copped) and not IsEntityDead(susped) then
9588 local posc = GetEntityCoords(copped, true)
9589 local poss = GetEntityCoords(susped, true)
9590 local dist = Vdist(posc.x, posc.y, posc.z, poss.x, poss.y, poss.z)
9591 if (dist < 3) and IsPedStill(susped) then
9592 if GetPlayerPed(-1) == susped then
9593 if toggle == true then
9594 ShowNotification("~r~You have been handcuffed by " .. GetPlayerName(copp) .. ".")
9595 ShowNotification("~w~You have been removed from your faction/job.")
9596 SetPedRelationshipGroupHash(susped, GetHashKey("CIVMALE"))
9597 playerteam = team_civ
9598 TriggerServerEvent("setPlayerCuffed_s", true)
9599 RemoveAllPedWeapons(susped)
9600 ClearPedTasksImmediately(susped)
9601 iscuffed = true
9602 else
9603 ShowNotification("~y~Your handcuffs have been removed by " .. GetPlayerName(copp) .. ".")
9604 TriggerServerEvent("setPlayerCuffed_s", false)
9605 uncuffPed()
9606 end
9607 else
9608 if toggle == true then
9609 SendChatMessageWithRange("* " .. GetPlayerName(copp) .. " handcuffs " .. GetPlayerName(susp) .. ".", {col_me_r, col_me_g, col_me_b}, rng_chat_me)
9610 ShowNotification("~y~You have handcuffed " .. GetPlayerName(susp) .. ".")
9611 ShowNotification("~w~Use [ /unseat id ] to remove subject from vehicles.")
9612 else
9613 SendChatMessageWithRange("* " .. GetPlayerName(copp) .. " uncuffs " .. GetPlayerName(susp) .. ".", {col_me_r, col_me_g, col_me_b}, rng_chat_me)
9614 ShowNotification("~r~You have released " .. GetPlayerName(susp) .. ".")
9615 end
9616 end
9617 else
9618 if GetPlayerPed(-1) == copped then
9619 ShowNotification("~r~Target is not within range or is moving.")
9620 end
9621 end
9622 end
9623end)
9624
9625shell.run("label set flowerBuilder")
9626rednet.open("left")
9627
9628function leaf ()
9629 turtle.forward()
9630 turtle.down()
9631 turtle.placeDown()
9632 turtle.up()
9633 turtle.forward()
9634 turtle.placeDown()
9635 turtle.back()
9636 turtle.select(2)
9637 turtle.placeDown()
9638 turtle.turnLeft()
9639 turtle.forward()
9640 turtle.select(1)
9641 turtle.placeDown()
9642 turtle.back()
9643 turtle.turnRight()
9644 turtle.up()
9645 turtle.placeDown()
9646 turtle.back()
9647 turtle.down()
9648 turtle.turnLeft()
9649end
9650function flower ()
9651 leaf()
9652 leaf()
9653 leaf()
9654 leaf()
9655 turtle.select(2)
9656 turtle.up()
9657 turtle.placeDown()
9658 turtle.select(1)
9659 turtle.up()
9660 turtle.placeDown()
9661end
9662
9663while true do
9664 id, msg, prot = rednet.receive()
9665 print(msg)
9666 if prot == "flower" then
9667 if msg == "flower" then
9668 flower()
9669 else
9670 shell.run(msg)
9671 end
9672 end
9673end
9674
9675direction="forward"
9676
9677function stepForward()
9678 if direction=="left" then
9679 turtle.turnLeft()
9680 elseif direction=="right" then
9681 turtle.turnRight()
9682 end
9683
9684 direction="forward"
9685
9686 if turtle.forward() then
9687 breakDown()
9688 end
9689end
9690
9691function breakDown()
9692 if turtle.detectDown() then
9693 local success,data = turtle.inspectDown()
9694
9695 if success==true then
9696 if data.name=="minecraft:wheat" and data.metadata=="7" then
9697 turtle.digDown()
9698 elseif data.name=="minecraft:wool" then
9699 if data.metadata==5 then
9700 direction="right"
9701 elseif data.metadata==14 then
9702 direction="left"
9703 end
9704 end
9705 end
9706 end
9707end
9708
9709repeat
9710 stepForward()
9711until false
9712
9713--[[Type !shop
9714the prices :-
9715Meep ~> 50 coins
9716Vampire ~> 100 coins
9717Shaman ~> 150 coins
9718Fly! ~> 200 coins]]
9719
9720data={}
9721dataplayer = {}
9722
9723function Shop(name)
9724 data[name].openShop=true
9725 ui.addTextArea(60, "", name, 160, 183, 378, 89, 0x2c555c, 0x936240, 1, true)
9726 ui.addTextArea(61, "", name, 162, 185, 374, 85, 0x324650, 0x152d30, 1, true)
9727 ui.addTextArea(65, "<b><p align='center'><J>Fly", name, 184, 197, nil, nil, 0x2e2e2e, 0x2e2e2e, 1, true)
9728 ui.addTextArea(63, "<b><p align='center'><G>Vampire", name, 362, 197, nil, nil, 0x2e2e2e, 0x2e2e2e, 1, true)
9729 ui.addTextArea(64, "<b><p align='center'><VP>Shaman", name, 446, 197, nil, nil, 0x2e2e2e, 0x2e2e2e, 1, true)
9730 ui.addTextArea(67, "<b><p align='center'><R>Meep!", name, 270, 197, nil, nil, 0x2e2e2e, 0x2e2e2e, 1, true)
9731 ui.addTextArea(28, "<p align='center'><b>"..data[name].vampp.."", name, 372, 241, nil, nil, 0x324650, 0x000000, 0, true)
9732 ui.addTextArea(29, "<p align='center'><b>"..data[name].shamann.."", name, 454, 241, nil, nil, 0x324650, 0x000000, 0, true)
9733 ui.addTextArea(30, "<p align='center'><b>"..data[name].meepp.."", name, 278, 241, nil, nil, 0x324650, 0x000000, 0, true)
9734 ui.addTextArea(71, "<p align='center'><b>"..data[name].flyy.."", name, 190, 241, nil, nil, 0x324650, 0x000000, 0, true)
9735 ui.addTextArea(33, "", name, 310, 135, 79, 29, 0x2c555c, 0x936240, 1, true)
9736 ui.addTextArea(32, "<p align='center'><b><VI>"..data[name].coins.." $", name, 312, 137, 75, 25, 0x324650, 0x152d30, 1, true)
9737 ui.addTextArea(35, "", nil, 308, 294, 79, 29, 0x2c555c, 0x936240, 1, true)
9738 ui.addTextArea(34, "<p align='center'><b><R><a href='event:close'>Close", nil, 310, 296, 75, 25, 0x324650, 0x152d30, 1, true)
9739end
9740
9741function closeShop(name)
9742 data[name].openShop=false
9743 for areas,k in pairs({60,61,65,63,64,67,28,29,30,71,33,32,35,34}) do
9744 ui.removeTextArea(k,name)
9745 end
9746end
9747
9748function Dataplayer(name)
9749 for i,dataplayer in ipairs(dataplayer) do
9750 if name==dataplayer then
9751 return true
9752 end
9753end
9754return false
9755end
9756
9757function reData(name)
9758 data[name]={openShop=false,coins=0,fly=false,meepp="<a href='event:meep'>Buy",shamann="<a href='event:shaman'>Buy",vampp="<a href='event:vamp'>Buy",flyy="<a href='event:fly'>Buy"}
9759end
9760
9761function eventNewPlayer(name)
9762 if Dataplayer(name) then else
9763 reData(name)
9764 table.insert(dataplayer,name)
9765 end
9766 for keys, k in pairs({32}) do
9767 tfm.exec.bindKeyboard(name, k, true, true)
9768 end
9769end
9770
9771for name,player in pairs(tfm.get.room.playerList) do
9772 eventNewPlayer(name)
9773end
9774
9775function eventTextAreaCallback(ids,name,callback)
9776if callback=="meep" and 50 <= data[name].coins then
9777 data[name].meepp="<a href='event:eqm'>Use"
9778 data[name].coins=data[name].coins-50
9779 Shop(name)
9780elseif callback=="vamp" and 100 <= data[name].coins then
9781 data[name].vampp="<a href='event:eqv'>Use"
9782 data[name].coins=data[name].coins-100
9783 Shop(name)
9784elseif callback=="shaman" and 150 <= data[name].coins then
9785 data[name].shamann="<a href='event:eqs'>Use"
9786 data[name].coins=data[name].coins-150
9787 Shop(name)
9788elseif callback=="fly" and 200 <= data[name].coins then
9789 data[name].fly=true
9790 data[name].flyy="Purchased"
9791 data[name].coins=data[name].coins-200
9792 Shop(name)
9793elseif callback=="eqs" then
9794 tfm.exec.setShaman(name)
9795elseif callback=="eqv" then
9796 tfm.exec.setVampirePlayer(name)
9797elseif callback=="eqm" then
9798 tfm.exec.giveMeep(name)
9799elseif callback=="close" then
9800 closeShop(name)
9801 end
9802end
9803
9804function eventChatCommand(name,c)
9805 if c=="shop" then
9806 Shop(name)
9807 end
9808end
9809
9810function eventLoop()
9811 for name,player in pairs(tfm.get.room.playerList) do
9812 data[name].coins=data[name].coins+1
9813 if data[name].openShop==true then
9814 ui.addTextArea(32, "<p align='center'><b><VI>"..data[name].coins.." $", name, 312, 137, 75, 25, 0x324650, 0x152d30, 1, true)
9815 end
9816 end
9817end
9818
9819function eventKeyboard(name, key, down, x, y)
9820 if key==32 and data[name].fly==true then
9821 tfm.exec.movePlayer(name,0,0,false,0,-40,false)
9822 end
9823end
9824
9825direction="forward"
9826inverse=false
9827
9828function stepForward()
9829 if direction=="left" then
9830 turtle.turnLeft()
9831 elseif direction=="right" then
9832 turtle.turnRight()
9833 end
9834
9835 direction="forward"
9836
9837 if turtle.forward() then
9838 breakDown()
9839 end
9840end
9841
9842function breakDown()
9843 if turtle.detectDown() then
9844 local success,data = turtle.inspectDown()
9845
9846 if success==true then
9847 if data.name=="minecraft:wheat" and data.metadata=="7" then
9848 turtle.digDown()
9849 elseif data.name=="minecraft:wool" then
9850 if data.metadata==5 then
9851 direction=inverse and "left" or "right"
9852 elseif data.metadata==14 then
9853 direction=inverse and "right" or "left"
9854 elseif data.metadata==4 then
9855 inverse = not inverse
9856 end
9857 end
9858 end
9859 end
9860end
9861
9862repeat
9863 stepForward()
9864until false
9865
9866function arm()
9867turtle.select(15)
9868turtle.turnLeft()
9869turtle.turnLeft()
9870turtle.place()
9871for c = 1, 13 do
9872turtle.select(c)
9873turtle.drop()
9874end
9875turtle.select(15)
9876turtle.dig()
9877turtle.select(1)
9878turtle.turnLeft()
9879turtle.turnLeft()
9880minerar()
9881end
9882
9883function bau()
9884turtle.select(16)
9885turtle.turnLeft()
9886turtle.turnLeft()
9887turtle.place()
9888turtle.select(14)
9889turtle.suck(49)
9890turtle.select(16)
9891turtle.dig()
9892turtle.turnLeft()
9893turtle.turnLeft()
9894turtle.select(1)
9895reaba()
9896end
9897
9898function reaba()
9899slotd = turtle.getItemCount(14)
9900if slotd <= 15 then
9901bau()
9902else
9903turtle.select(14)
9904turtle.refuel(10)
9905minerar()
9906end
9907end
9908
9909function minerar()
9910if turtle.getFuelLevel() <= 30 then
9911reaba()
9912else
9913turtle.dig()
9914turtle.forward()
9915turtle.digDown()
9916turtle.digUp()
9917turtle.turnLeft()
9918turtle.dig()
9919turtle.forward()
9920turtle.digUp()
9921turtle.digDown()
9922turtle.turnRight()
9923turtle.turnRight()
9924turtle.forward()
9925turtle.dig()
9926turtle.forward()
9927turtle.digUp()
9928turtle.digDown()
9929turtle.turnLeft()
9930turtle.turnLeft()
9931turtle.forward()
9932turtle.turnRight()
9933arm()
9934end
9935end
9936
9937function ins()
9938turtle.select(16)
9939print("Coloque o bau vazio onde a turtle esta selecionado")
9940sleep(5)
9941det = turtle.getItemCount(16)
9942if det == 1 then
9943turtle.select(15)
9944print("Coloque o bau com carvao onde a turtle esta selecionando")
9945sleep(3)
9946if turtle.getItemCount(15) == 1 then
9947term.clear()
9948turtle.select(1)
9949minerar()
9950else ins()
9951end
9952else ins()
9953end
9954end
9955ins()
9956minerar()
9957
9958term.setBackgroundColor(colors.black)
9959shell.run("clear")
9960term.setCursorPos(11,3)
9961term.setBackgroundColor(colors.green)
9962term.setTextColor(colors.black)
9963print(" Speicher ")
9964term.setBackgroundColor(colors.red)
9965term.setTextColor(colors.white)
9966term.setCursorPos(41,3)
9967print("X")
9968term.setTextColor(colors.black)
9969term.setBackgroundColor(colors.white)
9970term.setCursorPos(11,4)
9971print(" ")
9972term.setCursorPos(11,5)
9973print(" ")
9974term.setCursorPos(11,6)
9975print(" ")
9976term.setCursorPos(11,7)
9977print(" ")
9978term.setCursorPos(11,8)
9979print(" ")
9980term.setCursorPos(11,9)
9981print(" ")
9982term.setCursorPos(11,10)
9983print(" ")
9984term.setCursorPos(11,11)
9985print(" ")
9986term.setCursorPos(11,12)
9987print(" ")
9988term.setCursorPos(11,13)
9989print(" ")
9990term.setCursorPos(11,14)
9991print(" ")
9992term.setCursorPos(11,15)
9993print(" ")
9994term.setCursorPos(11,16)
9995print(" ")
9996term.setCursorPos(11,17)
9997print(" ")
9998term.setCursorPos(12,5)
9999print("Freier Speicherplatz: 7,5 GB")
10000term.setCursorPos(12,7)
10001print("Belegter Speicherplatz: 0,5 GB")
10002term.setCursorPos(12,9)
10003print("Davon Systemdaten: 100%")
10004term.setCursorPos(12,11)
10005print("Davon Nutzerdaten: 0%")
10006while true do
10007local event, button, X, Y = os.pullEvent("mouse_click")
10008XY = X..","..Y
10009
10010if XY == "41,3" and button == 1 then
10011shell.run("nilles/desktop_green")
10012break
10013end
10014end