TPT Script Server

This page is used for previewing and submitting scripts for use with the Script Manager

Available Scripts

(2) TPTMulti by LBPHacker
(3) set wifi v2 by jacob1
(4) Script Paste by jacob1
(5) Random Element by jacob1
(6) Magical Merge Master 3000 by nucular
(7) More Fuel Mod-heavy by jward212
(9) Breakpoints (BRPT) by boxmein
(10) Cockroaches! by boxmein
(11) Random tree by ssccsscc
(12) Element with random properties by ssccsscc
(15) Minimalistic Element Dehider by nucular
(16) FPS Gauge by mniip
(17) TPT Radio by jward212
(18) Print Debugger by FeynmanLogomaker
(19) Powered BHOL by jacob1
(20) Light and lamps by electronic_steve
(21) Extremely Durable TTAN by QuentinADay
(22) New Buttons by QuentinADay
(23) Pure Energy by QuentinADay
(25) RCA's HUD XV Update I by RCAProduction
(27) 123456787654 vols by mjpowder
(28) Singularity Bomb by QuentinADay
(29) ES wifi set by electronic_steve
(30) Lua Elements Pack by FeynmanLogomaker
(31) stkm gun by jward212
(32) space building materials by kjack1111
(34) Rust bomb by Damian97
(35) Simple command block by ssccsscc
(36) Everlasting Fusion by QuentinADay
(37) Screenshot Organiser by mecha-man
(38) Napalm mod by cccp3
(39) Rocket fuel mod v0.15 by cccp3
(41) Useful web links by jward212
(42) TPT Logic Gates Mod by iamdumb
(43) ESTools by electronic_steve
(44) Head Crabs-HL2 by jward212
(45) Procedural Save Generator by boxmein
(46) smooth colours for nametag by jward212
(47) ZAKPACK by zak03
(49) Performance Monitor by FeynmanLogomaker
(51) Texter by byzod
(52) Texter default fonts by byzod
(53) Schicko's Font Pack for Texter by Schicko
(54) Realistic Element Names by Atomic10
(55) TPT's Mod V.3 Update 1 by Amy
(56) Temporaryaccount-Decorator by Temporaryaccount
(57) random save loader by jward212
(58) Tmp gradient display by ssccsscc
(59) particle re-orderer by mniip
(60) Electric Glow by jacob1
(61) More Fuel Mod-lite by jward212
(63) Rythidium by janekbe04
(64) Simple FPS GUI by Sfsjunior
(65) Enhanced Element Dehider by ChargedCreeper
(66) Graph of average temp by ssccsscc
(67) Template save loader by jacob1
(68) Lua Text Generator by jBot-42
(70) Pixel's Freezer by Pixelguru26
(71) Thingy | Fusion For Ever by TheChosenEvilOne
(72) op explosions by zolly_bro
(73) Scar by DorkyBobster
(74) ScreenShotMod by lill74
(77) Useful Things by TheEvilChosenOne
(78) Alchemy Mod by _MrN_
(79) Nuke v2 by Fnaf65
(80) Compressor mod by TheChosenEvilOne
(81) Custom Render Mode Loader by jacob1
(82) Spacewars by JosephMA
(83) MOAR - Alpha 0.1 by TheChosenEvilOne
(86) Element Creator by cxi
(88) Soapworm by LBPHacker
(90) Pressure Bomb by God_Kra
(91) SMFB by wntjq69
(92) Potato by cxi
(93) Subatomic Pack (BDS) by TPT_PL
(94) Acidic Pack (BDS) by TPT_PL
(95) Starbound Building Materials by Sanpypr
(96) Factory problems by TPT_PL
(97) Gamma Ray-diation by Kostia4381
(98) Magic by livingfossil
(99) Cross-window Copy/Cut/Paste by LBPHacker
(100) Langton's Ant with variations by LBPHacker
(101) Remote particle creator/deleter by TPT_PL
(102) Force fields by electronic_steve
(103) Reinforced Concrete by 12Me21
(105) TPT_PL's Lua Mod by TPT_PL
(106) Nuke v4 by Fnaf65
(107) CHEMMOD V1 by KevAK
(108) Chemicals by Ligan
(109) VonDaniel's Template by VonDaniel
(110) The Inaccurate Radioactivity Toy Mod by TuDoR2007
(112) textmonsterPack by textmonster404
(113) Meteor by TheScienceKid
(114) Tgpm by TuDoR2007
(115) Civilizations by TPT_PL
(116) RAD-MOD 1.2.1B by Kev_AK
(117) MicroLua by RamiLego4Game
(118) Extra customizable HUD by djy0212
(119) Ingame brush editor by ssccsscc
(120) Window Maker by Paul_31415
(121) CHEM-MOD V1.2B by Kev_AK
(122) Rainbow PHOT by Mrprocom
(123) stronger stickmanv by yuval
(124) 3D Pressure Visualizer by mniip
(125) Arkadian Liquid by JanKaszanka
(126) Fuel by nukers473
(127) Immersive Radioactivity v2.1 by Potbelly
(128) ElementLaunchingTool by juh9870
(129) CHEM-MOD_v1.2.2b by KevAK
(130) Slingshot by Mrprocom
(131) Perlin Noise Generator by DoubleF
(132) Element Replace by TomW1605
(133) Flooder V2 by TheAwesomeMutant
(134) Link Sign GUI by QuanTech
(135) Element dehider by 4e616d65
(136) Subphoton ROM Builder by mad-cow
(137) Hardened Dust by Liftski
(138) Bio-Vir by TheAwesomeMutant
(140) Orbit Simulator by Mrprocom
(141) johnnyou's Font for Texter by johnnyou (49796346)
(142) auto_wifi by phisically
(143) Layering helper by ssccsscc
(144) Layering Helper Extended by LuaMaster
(145) TPT Remade by TuDoR2007
(146) All-seeing sampler by djy0212
(147) Layering helper remastered by ssccsscc
(148) Eraser by thepowdertoy12
(149) EXPLOSIONS by olix3001
(150) Simple rocket fuel mod by ArseniyPlotnikov2006
(151) Pure Fission by Fnaf65
(154) Graph by ssccsscc
(155) Little's Pack! by LittleProgramming
(156) Lead by LoftisGaming
(157) WIFI Tuner by ssccsscc
(158) Previous Brush by TomW1605
(159) HUD Auto-Hider by Tim
(161) Stack tool by thepowdertoy12
(162) Oil and plastic by ArseniyPlotnikov2006
(163) Colored Ember by DUC
(164) Timer by ssccsscc
(165) Bacteria Mod by TuDoR2007
(166) Noise filter by LBPHacker
(167) Future-proof element dehider by LBPHacker
(168) RadioactiveNuke by DreamingWarlord
(169) Only Hot Element by DreamingWarlord
(170) Philosopher's Stone by Godhydra
(171) Conic section generator by LBPHacker
(172) Interface API by ssccsscc
(173) Metals&Materials by Ferrous26
(174) tpt.all by LBPHacker
(175) The Visual Elements Pack by Goblin01, vvv331
(176) Layering Helper Reforged by PowderNotSolid
(177) SNOWified SING by LBPHacker
(178) FPS Chart by Goblin01
(179) TPT font writer by Goblin01
(180) Simple Ruler by PowderNotSolid
(181) Heat Modifier by DreamingWarlord
(182) TPT Remade II by TuDoR2007
(183) Gravity simulator by ArseniyPlotnikov2k6
(184) Unobtainium by christheboss894
(185) TPTMIDI noteblock in tpt by djy0212
(186) DreamingWarlord's Lua Tool by DreamingWarlord
(187) Elements Tooltip by Goblin01
(189) Explodium script by 0d15ea5ebe57c0debadc0ffee0ddf00d
(190) more powered force elements by 6nop6nop
(191) Yzaak1Scifire Modpack by Yzaak1Scifire
(194) Fluor and more modpack! by galaktor
(195) Hot Powder by lieve_blendi
(196) Star by TUANMINHVIETNAM
(197) Heat Powders by lieve_blendi
(200) Tangeriinium (thx 2 cxi 4 code) by LostEditor
(201) Freezer by lieve_blendi
(202) Powder Power! by TPTSortaGuy
(203) PowderPlus v1.4 by PowderPlus Team
(204) fire by ME
(205) Stacked Goo Animations by Maticzpl
(206) Stickman Control for Android Version by PhauloRiquelme
(207) Spark Removal Button by Xyz
(208) More HEAC's! by Maxhd1234
(209) Immersive Radioactivity v3.0 by Potbelly
(210) Subframe Chipmaker Script by Maticzpl
(211) Realistic Propellants by ArseniyPlotnikov2k6
(212) Mass Equals Gravity by Maticzpl
(213) PhiMod v1 by ArolaunTech
(214) PC Controls for Android by Cracker1000
(217) Single-pixel pipe configurator by LBPHacker
(218) Omega Death Laser Gun by Dogeoum
(219) Notifications by Maticzpl
(221) Powderizer by ArolaunTech
(222) ElemDehider 1.2 by Inventor70
(223) Unobtainum V2 by DoomKittyAttack
(224) Organics Mod v0.2B by PowderPlus Team
(225) Gravity distortion by Avolte55
(226) tmp Wifi by PhauloRiquelme
(227) Alchemagica Mod v1.0 by RebMiami
(228) Fan Elements Mod by RebMiami
(229) Impossibilities by ArolaunTech
(230) Realistic Explosives by ArseniyPlotnikov2k6
(231) libactivation by anamorphic
(232) Alloy Brushes by Maticzpl
(233) Gravity bender by pres
(234) Slow Tick by Pixel
(235) Paste ID by Maticzpl
(236) many things by jadenflp2
(237) Territect by Rebmiami
(238) Better Descriptions v1.0.5 by ashyboi2022
(239) LIGHTNING SPRK by GOLmaster10101
(240) Small Bombs by juh9870
(241) Save Shop by aaccbb
(242) Moving solids v1.3.0 Beta by ArolaunTech
(244) Alchemistry by rdococ
(245) ETRD (Formerly PowderIM) by aaccbb
(246) RadonX by Justadirtblock
(248) Water-X by deuterium_oxide
(250) Indestructible INSL by CheekyRand0m
(252) Console's Mod by Console/Compec
(255) Slow motion by LBPHacker
(256) Powered Repeller by Hythonia
(257) Zeta's Electric Tools. by Zetalasis
(258) Azure serum (AZSR) by ALumpOfPowderToy
(259) COLORFULSAND by xert
(260) Lightning Circle by defaultuser0
(261) Powder Future Tech by JonaHungary
(262) TPTGlowingSolids by DestinyDyson
(263) Volcano Bomb by I_am_the_NugsWorld
(264) Neon Lights by Rebmiami
(265) Radioactive Materials by xyz
(266) Eater mod by VIPERGAMEZ
(267) the biology mod by someone
(268) Atomic Physics by qe
(269) Pure Radiation by ronansb
(270) Fake Elements by That_PowderToy_Guy
(271) Tachyons and MISC by RamenNoods
(272) Exotic Particles by rdococ
(273) FPS Slider by aaccbb
(274) Enphosian's Radioactive mod pack by Enphosian
(276) ROM Builder by QnpfvTPz

+ Submit new script!

Title: Author:
Script:
--Version 2.8_hotfix1 (2.x final)
--Author: djy0212
--Email: "moc.liamxof)ta(2120yjd" in reverse
--Will not add more features, only bugfixes

--[[
All-seeing Eye Sampler(or silk touch in tpt) manual

1.Introduction
    All-seeing Eye Sampler is a script that provides some convenient tools to better create mixtures and special particles. It contains two pseudo-elements in the "Tools" menu. One is an eye in a triangle and the other is some falling particles. There are four modes of the tool which are "pixel mode", "random mode", "pattern mode" and "layering mode". With the tool, you can create *exact* copies of a particle, mixtures of particles either randomly or regularly, or make layered materials with ease. Nearly all operations that requires you to copy a few pixels again and again can be simplified to just a few keypresses and clicks.
    All operations in this script is done via the two tools in the "tools" menu and keyboard. Let's call the tool with a triangle eye icon "eye tool" or "sampler", and call the other with particles "particles tool". When the eye tool is selected, you can press "home" key to cycle among modes.
    Each mode has its hotkey, but there are some global hotkeys.
    Global hotkeys(while selecting the "eye" tool):
        End:      Switch 'velocity sampler', useful for sampling energy particles
        Home:     Switch among modes
        ScrLock:  Select "particle" tool
    
    Global hotkeys(while selecting the "particle" tool):
        Delete:   Clear selected sample
        ScrLock:  Select "eye" tool
    
    Also, you can press ScrLock(Scroll Lock) any time to quickly select the "eye" tool.

2.Modes
    (1).Pixel mode
        +--------+
        |AAAAAAAA|
        |AAAAAAAA|
        |AAAAAAAA|
        +--------+
        The default mode. In this mode, click any particle with the eye tool to sample it. It will sample the element with its all properties. Then use the particle tool to draw the sample.
    
    (2).Random mode
        +--------+
        |BABABCCB|
        |AABACAAA|
        |BCBCABCA|
        +--------+
        This is the second mode so press "home" one time while holding the eye tool to reach it. When you are in this mode, you can draw particle mixtures.
        Firstly, put all particles you want to mix on the screen. Then use the eye tool and click each one type of the particles one time. A message of the current particle and total amount of particles will appear. When you finished sampling, you can adjust the weight of each particle by selecting it in the particle list (Use "page up" and "page down" to navigate) and press "+" or "-" on the numpad. 
        The particle with a higher weight is more likely to appear in the mixture and vice versa.
        You can use "/" on the numpad to insert a "empty" particle to the particle list. Try to increase the weight and it can make an effect of spray brush.
        Hotkeys(while selecting the "eye" tool):
            PageUp:   Moves the pointer to the previous particle in the particle list
            PageDown: Moves the pointer to the next particle in the particle list
            Delete:   Delete the target particle
            +:        Increase the weight of target particle
            -:        Decrease the weight
            *:        View the info of target particle
            /:        Replace the target particle with "the air"(or "Empty")
    (3).Pattern mode
        +--------+
        |ABABABAB|
        |ABABABAB|
        |ABABABAB|
        +--------+
        In this mode, you can draw particle patterns. Press "+" on the numpad first to set the pattern size. Then position your cursor on the upper left corner of the pattern drawn,and press "/" on the numpad to copy the pattern. If you click it, it will only sample the one under your cursor.
        Advanced usage:
            There's a pointer just like that in random mode, but it's 2-dimensional. Use arrow keys to navigate. Click with the eye tool to put the particle under the cursor to the target particle.
        
        Control keys(while selecting the "eye" tool):
            +:          Set the size of the pattern
            Arrow keys: Move the pointer
            Delete:     Delete the target particle
            -:          Set pattern offset
            *:          View detailed info
            /:          Sample pattern
    (4).Layering mode
            +--------+
          +-|CCCCCCCC|
        +-|B|CCCCCCCC|
        |A|B|CCCCCCCC|
        |A|B+--------+
        |A+--------+
        +--------+
        In this mode, you can stack particles up to 5 layers. Use it just like random mode.
        Control keys(while selecting the "eye" tool):
            PageUp:   Moves the pointer to the previous particle
            PageDown: Moves the pointer to the next particle
            Delete:   Delete the target particle
            *:        View the info of target particle
            /:        Sample existing stack

3.Save & Load
    Press "insert" when selecting eye or particle tool to enter save&load mode. In this mode, the icon of the eye tool will turn to blue, which means "save". The icon of the particle tool will turn to yellow, which means "load". Press "insert" again when selecting particle(load) tool to return to normal mode.
    (1).Save
        Click the eye tool and an input box will appear. Enter the name of the file, and it will be saved in the "samples" folder in your game directory. It can be copied and shared with other people.
    (2).Load
        Click the particle tool and if there's any sample, a file list will be rendered on the screen. Use arrow keys, pageup and pagedown to navigate through those files. Press numpad "+" to load one. You can also press numpad "-" and manually input the file name.
        When in the load interface, you can press numpad "/" to copy the sample you are holding (NOT that you selected in the file list) to the clipboard (in a text form). This can be shared and loaded into others' game by press numpad "*" in this interface.
        Control keys:
            +:          Load file
            Arrow keys, PageUp and PageDown: 
                        Move the selection
            Delete:     Delete the selected file
            -:          Manually input the file name
            /:          Copy sample to clipboard
            *:          Load sample from clipboard
            End:        Refresh file list
            Home:       Recalculate preview color (will lose holding sample)

4.
    If you have any problem, please try reading the (messy garbage) source and modify it by yourself.
    You can also email me or PM me.

]]--

HUD_MODE = 0 -- 0:fixed, 1:follow cursor
HUD_POS_X = 12
HUD_POS_Y = 51

local keys
local chars
--use sdl2 key code
if (tpt.version["jacob1s_mod"] ~= nil and tpt.version["jacob1s_mod"] >= 42) or (tpt.version["major"] >= 94) then
    keys = {
        ["insert"] = 0x40000049,
        ["delete"] = 127,
        ["home"  ] = 0x4000004a,
        ["end"   ] = 0x4000004d,
        ["pgup"  ] = 0x4000004b,
        ["pgdn"  ] = 0x4000004e,
        ["num/"  ] = 0x40000054,
        ["num*"  ] = 0x40000055,
        ["num-"  ] = 0x40000056,
        ["num+"  ] = 0x40000057,
        ["up"    ] = 0x40000052,
        ["down"  ] = 0x40000051,
        ["left"  ] = 0x40000050,
        ["right" ] = 0x4000004F,
        ["num1"  ] = 0x40000059,
        ["num2"  ] = 0x40000060,
        ["scrlck"] = 0x40000047
    }
else
    keys = {
        ["insert"] = 277,
        ["delete"] = 127,
        ["home"  ] = 278,
        ["end"   ] = 279,
        ["pgup"  ] = 280,
        ["pgdn"  ] = 281,
        ["num/"  ] = 267,
        ["num*"  ] = 268,
        ["num-"  ] = 269,
        ["num+"  ] = 270,
        ["up"    ] = 273,
        ["down"  ] = 274,
        ["left"  ] = 276,
        ["right" ] = 275,
        ["num1"  ] = 257,
        ["num2"  ] = 258,
        ["scrlck"] = 71
    }
end
if (tpt.version["major"] < 94 or tpt.version["jacob1s_mod"] ~= nil) then -- old version ascii characters
    chars = {
        ["eye"] = "\xa3",
        ["eye_elem"] = "\xa3",
        ["part_elem"] = "\x9a",
        ["part"] = "\x9a",
        ["save"] = "\x82",
        ["load"] = "\x81"
    }
elseif (tpt.version["major"] == 94 and tpt.version["minor"] <= 1) then -- use unicode symbols and compat
    chars = {
        ["eye"] = "\xee\x80\xa3",
        ["eye_elem"] = "/0\\",
        ["part_elem"] = "!!!",
        ["part"] = "\xee\x80\x9a",
        ["save"] = "\xee\x80\x82",
        ["load"] = "\xee\x80\x81"
    }
else -- unicode element name should be fixed now
    chars = {
        ["eye"] = "\xee\x80\xa3",
        ["eye_elem"] = "\xee\x80\xa3",
        ["part_elem"] = "\xee\x80\x9a",
        ["part"] = "\xee\x80\x9a",
        ["save"] = "\xee\x80\x82",
        ["load"] = "\xee\x80\x81"
    }
end

local moden = 0
local mode_max_n = 3
--0:single pixel, 1:random mixed, 2:pattern mixed, 3:layered
local modes = {}
local save = {}
modes[0] = {
    name = 'Pixel',
    thepixel={},
    tooltips = {pked = "A perfectly-sampled particle.",pick = "Sample a particle on the screen EXACTLY.", color = 0x000000}
}
modes[1] = {
    name = 'Random',
    list = {},
    selected_number = 1,
    tooltips = {pked = "Some random-mixed particles.",pick = "Mix several particles on the screen RANDOMLY.", color = 0xffffff}
}
modes[2] = {
    name = 'Pattern',
    list = {},
    width = 0,
    height = 0,
    ptr_lr = 1,
    ptr_ud = 1,
    x_offset = 0,
    y_offset = 0,
    tooltips = {pked = "Some regularly-mixed particles.",pick = "Put several particles together REGULARLY", color = 0x7f7f7f}
}

modes[3] = {
    name = 'Layering',
    list = {},
    selected_number = 1,
    tooltips = {pked = "A stack of particles.",pick = "Stack them ALL!", color = 0x7f3f3f}
}

modes[233] = {
    name = 'Save & Load',
    file_list = {},
    selected_file_number = 1,
    tooltips = {pked = chars["load"].." Load",pick = chars["save"].." Save", color1 = 0x6b94ce, color2=0xf7de62},
    tosave_mode = 0,
    color_data = {}
}

local unpack = unpack or table.unpack

math.randomseed(tostring(os.time()):reverse():sub(1, 7))

local id_picker = 'PICKER_PT_PICK'
local id_picked = 'PICKER_PT_PKED'
local el_picker = elem.allocate("picker","pick")
elem.element(el_picker, elem.element(elem.DEFAULT_PT_DMND))
elem.property(el_picker,"Name","["..chars["eye_elem"].."]") -- an icon of an eye
elem.property(el_picker,"Description","Sample a particle on the screen EXACTLY.")
elem.property(el_picker,"Colour",0x000000)
elem.property(el_picker,"HeatConduct",0)
elem.property(el_picker,"MenuSection",elem.SC_TOOL)
elem.property(el_picker,"HighTemperature",sim.MIN_TEMP)
elem.property(el_picker,"HighTemperatureTransition",0)
elem.property(el_picker,"Properties",elem.PROP_NOCTYPEDRAW)
elem.property(el_picker,"Properties", bit.band(elem.property(el_picker, "Properties"), bit.bnot(elem.PROP_DRAWONCTYPE)))

local function picker_gfx(i, colr, colg, colb)
    if i ~= 0 then
        sim.partKill(i) -- remove garbage, make sure that it will be removed paused or unpaused
    end
    return 1, ren.PMODE_NONE, 0, 0, 0, 0
end

elem.property(el_picker, "Graphics", picker_gfx)

local el_picked = elem.allocate("picker","pked")
elem.element(el_picked, elem.element(elem.DEFAULT_PT_DMND))
elem.property(el_picked,"Name","["..chars["part_elem"].."]") --an icon of some particles
elem.property(el_picked,"Description","A perfectly-sampled particle.")
elem.property(el_picked,"Colour",0x000000)
elem.property(el_picked,"HeatConduct",0)
elem.property(el_picked,"MenuSection",elem.SC_TOOL)
--elem.property(el_picked,"HighTemperature",sim.MIN_TEMP)
--elem.property(el_picked,"HighTemperatureTransition",0)
elem.property(el_picked, "Properties", bit.band(elem.PROP_NOCTYPEDRAW, bit.bnot(elem.PROP_DRAWONCTYPE)))

--replace the placed PKED
local function picked_gfx(i, colr, colg, colb)
    modes[moden].pked_handler() -- there must be at least 1 pked, replace them all
    return 0, ren.PMODE_FLAT , 0, colr, colg, colb
end

elem.property(el_picked, "Graphics", picked_gfx)

--from lbphacker,modified
local PROPERTIES = {}
local prop_vel_enabled = false
local function gen_prop_list(enable_vel)
    prop_vel_enabled = enable_vel
    PROPERTIES = {}
    for key, value in next, sim do
        if key:find("^FIELD_") and key ~= "FIELD_X" and key ~= "FIELD_Y" and (key ~= "FIELD_VX" or enable_vel) and (key ~= "FIELD_VY" or enable_vel) then
            PROPERTIES[key] = true
        end
    end
end

gen_prop_list(false)

local function pick_part(pixel,part_index)
    for key in next, PROPERTIES do
        pixel[key]=sim.partProperty(part_index, sim[key])
    end
end

local function create_part(pixel,x,y)
    local idx = sim.partCreate(-1,x,y,pixel['FIELD_TYPE'] or 0)
    if idx == 0 then
        return
    end
    for key in next, PROPERTIES do
        if key ~= 'FIELD_TYPE' then
            sim.partProperty(idx,sim[key],pixel[key] or 0)
        end
    end
end

local function replace_part(pixel,part_index)
    sim.partProperty(part_index,sim.FIELD_TYPE,pixel['FIELD_TYPE'] or 0)
    for key in next, PROPERTIES do
        if key ~= 'FIELD_TYPE' then
            sim.partProperty(part_index,sim[key],pixel[key] or 0)
        end
    end
end

local function reverseTable(tab)
    local tmp = {}
    for i = 1, #tab do
        local key = #tab
        tmp[i] = tab[#tab-i+1]
    end
    
    return tmp
end

local function restrict_ptr(ptr,max,offset)
    if ptr+offset < 1 then
        return 1
    end
    if ptr+offset > max then
        return max
    end
    return ptr+offset
end

modes[0].pked_handler = function()
    for index in sim.parts() do
        if sim.partProperty(index,sim.FIELD_TYPE) == el_picked then
            replace_part(modes[0].thepixel,index)
        end
    end
end

modes[0].quick_pked_color = function()
    if modes[0].thepixel['FIELD_TYPE'] then
        return elem.property(modes[0].thepixel['FIELD_TYPE'],"Colour")
    else
        return 0x000000
    end
end

--from internet
modes[1].WeightedRandomSelect = function(innerTable)
    local totalWeight = 0

    -- Sum the weight values
    for _, t in ipairs(innerTable) do
        totalWeight = totalWeight + t[1]
    end

    -- Generate random number from 1 to the total weight
    local weightSelect = math.random(1, totalWeight)
    local thisThing = 0

    -- Check every row of the inner table till we find one smaller than our random number, then return it
    for sumdumvar, weight in ipairs(innerTable) do
        thisThing = thisThing+(innerTable[sumdumvar][1])
        if (weightSelect <= thisThing) then
            return innerTable[sumdumvar][2]
        end
    end
end

modes[1].pked_handler = function()
    ran_list = modes[1].list
    if next(ran_list) == nil then
        ran_list = {{1,{['FIELD_TYPE']=0}}} -- to prevent placing PKED when no element is sampled(random mode)
    end
    local total_weight = 0
    for index in sim.parts() do
        if sim.partProperty(index,sim.FIELD_TYPE) == el_picked then
            replace_part(modes[1].WeightedRandomSelect(ran_list),index)
        end
    end
end

local function avg_color(list)
    local totalR,totalB,totalG,n = 0,0,0,0
    for _,item in ipairs(list) do --average color
        local rgb_color = elem.property(item[2]['FIELD_TYPE'],"Colour")
        totalR = totalR + item[1]*bit.rshift(bit.band(0xff0000,rgb_color),16)--R
        totalG = totalG + item[1]*bit.rshift(bit.band(0x00ff00,rgb_color),8) --G
        totalB = totalB + item[1]*bit.band(0x0000ff,rgb_color) --B
        n = n + item[1]
    end
    totalR = math.floor(totalR/n)
    totalG = math.floor(totalG/n)
    totalB = math.floor(totalB/n)
    return bit.bor(bit.lshift(totalR,16),bit.lshift(totalG,8),totalB)
end

modes[1].quick_pked_color = function()
    return avg_color(modes[1].list)
end

modes[2].quick_pked_color = function()
    local totalR,totalB,totalG = 0,0,0
    for _,item in ipairs(modes[2].list) do --average color without freq.
        for _,jtem in ipairs(item) do
            if jtem then
                local rgb_color = elem.property(jtem['FIELD_TYPE'],"Colour")
                totalR = totalR + bit.rshift(bit.band(0xff0000,rgb_color),16)--R
                totalG = totalG + bit.rshift(bit.band(0x00ff00,rgb_color),8) --G
                totalB = totalB + bit.band(0x0000ff,rgb_color) --B
            end
        end
    end
    local n = modes[2].height*modes[2].width
    totalR = math.floor(totalR/n)
    totalG = math.floor(totalG/n)
    totalB = math.floor(totalB/n)
    local final_color = bit.bor(bit.lshift(totalR,16),bit.lshift(totalG,8),totalB)
    return final_color
end

modes[3].quick_pked_color = function()
    local totalR,totalB,totalG = 0,0,0
    for _,item in ipairs(modes[3].list) do --average color without freq.
        if item then
            local rgb_color = elem.property(item['FIELD_TYPE'],"Colour")
            totalR = totalR + bit.rshift(bit.band(0xff0000,rgb_color),16)--R
            totalG = totalG + bit.rshift(bit.band(0x00ff00,rgb_color),8) --G
            totalB = totalB + bit.band(0x0000ff,rgb_color) --B
        end
    end
    totalR = math.floor(totalR/5)
    totalG = math.floor(totalG/5)
    totalB = math.floor(totalB/5)
    local final_color = bit.bor(bit.lshift(totalR,16),bit.lshift(totalG,8),totalB)
    return final_color
end

local function global_pked_color()
    elem.property(el_picked,"Colour",modes[moden].quick_pked_color())
end

modes[2].pked_handler = function()
    local x,y,sel_x,sel_y,sel_pixel
    for index in sim.parts() do
        if sim.partProperty(index,sim.FIELD_TYPE) == el_picked then
            x,y = sim.partPosition(index)
            sel_x = (x-modes[2].x_offset)%modes[2].width + 1
            sel_y = (y-modes[2].y_offset)%modes[2].height + 1
            --print(sel_x,sel_y)
            if not (modes[2].width==0 and modes[2].height==0) then
                sel_pixel = modes[2].list[sel_y][sel_x]
            else
                sel_pixel = nil
            end
            if sel_pixel then
                replace_part(sel_pixel,index)
            else
                replace_part({['FIELD_TYPE']=0},index)
            end
        end
    end
end

modes[3].pked_handler = function()
    local li = modes[3].list
    if next(li) == nil then
        li = {{1,{['FIELD_TYPE']=0}}} -- to prevent placing PKED when no element is sampled
    end
    for index in sim.parts() do
        if sim.partProperty(index,sim.FIELD_TYPE) == el_picked then
            local x, y = sim.partProperty(index,sim.FIELD_X), sim.partProperty(index,sim.FIELD_Y)
            sim.partKill(index)
            for _,item in ipairs(li) do
                a = item
                local i = sim.partCreate(-3, x, y, item['FIELD_TYPE'])
                replace_part(item,i)
            end
        end
    end
end

local function change_mode(mode)
    modes[0].thepixel = {}
    modes[1].list = {}
    modes[1].selected_number = 1
    mode2_def = {
        list = {},
        width = 0,
        height = 0,
        ptr_lr = 1,
        ptr_ud = 1,
        x_offset = 0,
        y_offset = 0
    }
    modes[3].list = {}
    modes[3].selected_number = 1
    for k,v in pairs(mode2_def) do
        modes[2][k] = v
    end
    elem.property(el_picked,"Colour",0x000000)
    if not mode then
        return
    end
    if mode == -1 then
        gen_prop_list(false)
        mode = 0
    end
    if 0 <= mode and mode <= mode_max_n then
        elem.property(el_picked,"Description",modes[mode].tooltips.pked)
        elem.property(el_picker,"Description",modes[mode].tooltips.pick)
        elem.property(el_picker,"Colour",modes[mode].tooltips.color)
    end
    moden = mode
end

local notice = ''
local notice_cd = 0
local max_notice_cd = 200

local function hud_plain(msg)
    notice = msg
    notice_cd = max_notice_cd
end

local function step_display()
    if notice_cd > 0 and tpt.hud() then
        local text = '-'..chars["eye"]..'- '..notice
        local backwidth = tpt.textwidth(text)+8
        local posx, posy
        if HUD_MODE == 0 then -- fixed
            posx = HUD_POS_X
            posy = HUD_POS_Y
        else -- follow cursor
            local mx,my = tpt.mousex,tpt.mousey
            if mx>612-backwidth then
                posx = mx - backwidth
            else
                posx = mx
            end
            if my>372 then -- 384-12
                posy = my - 12
            else
                posy = my
            end
        end
        graphics.fillRect(posx, posy, backwidth, 12, 0, 0, 0, 128)
        graphics.drawText(posx+3, posy+3, text, 255, 208, 16, math.floor(notice_cd/max_notice_cd*255))
        notice_cd = notice_cd - 1
    end
end

event.register(event.tick,step_display)

modes[1].hud_alert = function()
    local sel = modes[1].list[modes[1].selected_number]
    if sel then
        if sel[2]['FIELD_TYPE'] == 0 then
            hud_plain(modes[1].selected_number..' of '..#modes[1].list..', Weight: '..sel[1]..', Elem: (Empty)')
        else
            hud_plain(modes[1].selected_number..' of '..#modes[1].list..', Weight: '..sel[1]..', Elem: '..tpt.element(sel[2]['FIELD_TYPE']))
        end
    else
        hud_plain(modes[1].selected_number..' of '..#modes[1].list..', (blank)')
    end
end

modes[2].hud_alert = function(detail)
    local sel = modes[2].list[modes[2].ptr_ud][modes[2].ptr_lr]
    if sel and not detail then
        hud_plain('X: '..modes[2].ptr_lr..', Y: '..modes[2].ptr_ud..', Elem: '..tpt.element(sel['FIELD_TYPE']))
    elseif not sel and not detail then
        hud_plain('X: '..modes[2].ptr_lr..', Y: '..modes[2].ptr_ud..', (blank)')
    elseif sel and detail then
        hud_plain('W: '..modes[2].width..', H: '..modes[2].height..', Xoff: '..modes[2].x_offset..', Yoff: '..modes[2].y_offset..', X: '..modes[2].ptr_lr..', Y: '..modes[2].ptr_ud..', Elem: '..tpt.element(sel['FIELD_TYPE']))

    elseif not sel and detail then
        hud_plain('W: '..modes[2].width..', H: '..modes[2].height..', Xoff: '..modes[2].x_offset..', Yoff: '..modes[2].y_offset..', X: '..modes[2].ptr_lr..', Y: '..modes[2].ptr_ud..', (blank)')

    end
end

modes[3].hud_alert = function()
    local sel = modes[3].list[modes[3].selected_number]
    if sel then
        if sel['FIELD_TYPE'] == 0 then
            hud_plain(modes[3].selected_number..' of 5 layers, Elem: (Empty)')
        else
            hud_plain(modes[3].selected_number..' of 5 layers, Elem: '..tpt.element(sel['FIELD_TYPE']))
        end
    else
        hud_plain(modes[3].selected_number..' of 5 layers, (blank)')
    end
end

modes[2].pick_parts = function(x,y)
    modes[2].ptr_lr = 1
    modes[2].ptr_ud = 1
    modes[2].x_offset = x%modes[2].width
    modes[2].y_offset = y%modes[2].height
    for j=1,modes[2].height do
        for i=1,modes[2].width do
            local temp_pixel = {}
            local index = sim.partID(i+x-1,j+y-1)
            if index ~= nil then
                pick_part(temp_pixel,index)
            else
                temp_pixel = false
            end
            modes[2].list[j][i] = temp_pixel
        end
    end
    global_pked_color()
end

modes[3].pick_parts = function(x,y) -- pick layered particles
    local l = {}
    for index in sim.parts() do
        if #l == 5 then
            break
        end
        local x1,y1 = sim.partPosition(index)
        if x1 == x and y1 == y then
            local temp_pixel = {}
            pick_part(temp_pixel,index)
            table.insert(l,temp_pixel)
        end
    end
    modes[3].list = l
    global_pked_color()
end

--from internet
function string.split(str, delimiter)
    if str==nil or str=='' or delimiter==nil then
        return nil
    end
    
    local result = {}
    for match in (str..delimiter):gmatch("(.-)"..delimiter) do
        table.insert(result, match)
    end
    return result
end

local function serialize_pixel(pixel)
    local str = ''
    for key in next, PROPERTIES do
        str = str..','..key:sub(7,key:len())..':'..(tostring(pixel[key]) or '0')
    end
    return str:sub(2,str:len())
end

local function serialdumps_pixel(str)
    local prop_nh = str:split(',')
    local prop = {}
    for _,s in ipairs(prop_nh) do
        local ob_temp = s:split(':')
        prop['FIELD_'..ob_temp[1]] = tonumber(ob_temp[2])
    end
    return prop
end

modes[0].serialize = function()
    local str = 'MODE01@'
    str = str..serialize_pixel(modes[0].thepixel)
    return str
end

modes[0].serialdumps = function(str)
    if str:sub(1,7) ~= 'MODE01@' then return false end
    str = str:sub(8,str:len())
    change_mode()
    modes[0].thepixel = serialdumps_pixel(str)
    global_pked_color()
    return true
end

modes[1].serialize = function()
    local str = 'MODE02@'
    for _,weighted in ipairs(modes[1].list) do
        str = str..serialize_pixel(weighted[2])
        str = str..'#'..tostring(weighted[1])..'*'
    end
    return str:sub(1,str:len()-1)
end

modes[1].serialdumps = function(str)
    if str:sub(1,7) ~= 'MODE02@' then return false end
    str = str:sub(8,str:len())
    change_mode()
    local p1 = str:split('*')
    local res = {}
    for _,s in ipairs(p1) do -- s is 'pixel#freq'
        local temp_pair = s:split('#')
        local ttemp = temp_pair[1]
        temp_pair[1] = tonumber(temp_pair[2])
        temp_pair[2] = serialdumps_pixel(ttemp)
        table.insert(res,temp_pair)
    end
    modes[1].list = res
    global_pked_color()
    return true
end

modes[2].serialize = function()
    local str = 'MODE03@'
    str = str..tostring(modes[2].width)..','..tostring(modes[2].height)..','..tostring(modes[2].x_offset)..','..tostring(modes[2].y_offset)..'*'
    for ir,row in ipairs(modes[2].list) do
        for ic,pixel in ipairs(row) do
            if pixel then
                str = str..serialize_pixel(pixel)
                str = str..'#'..tostring(ir)..','..tostring(ic)..'*'
            end
        end
    end
    return str:sub(1,str:len()-1)
end

modes[2].serialdumps = function(str)
    if str:sub(1,7) ~= 'MODE03@' then return false end
    str = str:sub(8,str:len())
    change_mode()
    local p1 = str:split('*')
    local posinfo = table.remove(p1,1)
    posinfo = posinfo:split(',')
    for i,v in ipairs(posinfo) do posinfo[i] = tonumber(v) end
    local w,h
    w,h,modes[2].x_offset,modes[2].y_offset= posinfo[1],posinfo[2],posinfo[3],posinfo[4]
    modes[2].set_raw_size(h,w)
    for _,s in ipairs(p1) do -- s is 'pixel#coord'
        local temp_pair = s:split('#')
        local co = temp_pair[2]:split(',')
        modes[2].list[tonumber(co[1])][tonumber(co[2])] = serialdumps_pixel(temp_pair[1])
    end
    global_pked_color()
    return true
end

modes[3].serialize = function()
    local str = 'MODE04@'
    for _,pixel in ipairs(modes[3].list) do
        str = str..serialize_pixel(pixel)..'*'
    end
    return str:sub(1,str:len()-1)
end

modes[3].serialdumps = function(str)
    if str:sub(1,7) ~= 'MODE04@' then return false end
    str = str:sub(8,str:len())
    change_mode()
    local p1 = str:split('*')
    local res = {}
    for _,s in ipairs(p1) do
        table.insert(res,serialdumps_pixel(s))
    end
    modes[3].list = res
    global_pked_color()
    return true
end

local function picker_hook(x,y,button)
    local x2,y2 = sim.adjustCoords(x,y)
    if x > 611 or y > 383 then --prevent clicking out of scene
        return
    end
    if (tpt.selectedl==id_picker and button==1) or (tpt.selectedr==id_picker and button==2) or (tpt.selecteda==id_picker and button==3) then --corresponding buttons
        if sim.partID(x2,y2) == nil then
            return false
        end
        if moden == 1 then
            local pixel = {}
            pick_part(pixel,sim.partID(x2,y2))
            modes[1].list[modes[1].selected_number] = {1,pixel}
            modes[1].hud_alert()
            modes[1].selected_number = modes[1].selected_number + 1
        elseif moden == 0 then
            pick_part(modes[0].thepixel,sim.partID(x2,y2))
        elseif moden == 2 then
            if not (modes[2].width==0 and modes[2].height==0) then
                local temp_pixel = {}
                pick_part(temp_pixel,sim.partID(x2,y2))
                modes[2].list[modes[2].ptr_ud][modes[2].ptr_lr] = temp_pixel
                modes[2].hud_alert()
            else
                hud_plain('Set pattern size first! (Press "+")')
            end
        elseif moden == 3 then
            local pixel = {}
            pick_part(pixel,sim.partID(x2,y2))
            modes[3].list[modes[3].selected_number] = pixel
            modes[3].hud_alert()
            if modes[3].selected_number < 5 then
                modes[3].selected_number = modes[3].selected_number + 1
            end
        end
        --print(x2,y2,modes[0].thepixel['FIELD_TYPE'])
        global_pked_color() --change the color of 'pick'
        return false
    end
end

event.register(event.mousedown,picker_hook)

local function picker_hook_up(x,y,button)
    local x2,y2 = sim.adjustCoords(x,y)
    if x > 611 or y > 383 then --prevent clicking out of scene
        return
    end
    if (tpt.selectedl==id_picker and button==1) or (tpt.selectedr==id_picker and button==2) or (tpt.selecteda==id_picker and button==3) then --corresponding buttons
        if moden == 0 then -- mouse release after sampled in mode0
            tpt.selectedl=id_picked
        end
    end
end

event.register(event.mouseup,picker_hook_up)

modes[0].pick_key_handler = function(key)
end

modes[1].pick_key_handler = function(key)
    if key == keys["delete"] then
        if modes[1].list[modes[1].selected_number] then
            table.remove(modes[1].list,modes[1].selected_number)
            global_pked_color()
        end
    elseif key == keys["pgup"] then
        modes[1].selected_number = restrict_ptr(modes[1].selected_number,#modes[1].list,-1)
    elseif key == keys["pgdn"] then
        modes[1].selected_number = restrict_ptr(modes[1].selected_number,#modes[1].list+1,1)
    elseif key == keys["num-"] and modes[1].list[modes[1].selected_number] then
        if modes[1].list[modes[1].selected_number][1] > 0 then
            modes[1].list[modes[1].selected_number][1] = modes[1].list[modes[1].selected_number][1] - 1
            global_pked_color()
        end
    elseif key == keys["num+"] and modes[1].list[modes[1].selected_number] then
        modes[1].list[modes[1].selected_number][1] = modes[1].list[modes[1].selected_number][1] + 1
        global_pked_color()
    elseif key == keys["num*"] then
        --only an hud_alert
    elseif key == keys["num/"] then
        modes[1].list[modes[1].selected_number] = {1,{['FIELD_TYPE']=0}} --empty element
    else
        return
    end
    modes[1].hud_alert()
    return false
end

modes[2].proper_input = function(text1,text2)
    local whs = tpt.input(text1, text2)
    local n = string.find(whs,',')
    if n == nil then
        tpt.throw_error('Invalid format!')
        return false
    end
    local d1 = tonumber(string.sub(whs, 1, n - 1))
    local d2 = tonumber(string.sub(whs, n + 1, #whs))
    if type(d1) ~= 'number' or type(d2) ~= 'number' then
        tpt.throw_error('Invaild format!')
        return false
    end
    return d1,d2
end

modes[2].set_raw_size = function(d1,d2)
    modes[2].width,modes[2].height = d1,d2
    for i=1,modes[2].height do
        modes[2].list[i] = {}
        for j=1,modes[2].width do
            modes[2].list[i][j] = false
        end
    end
end

modes[2].set_pattern_size = function()
    local d1,d2 = modes[2].proper_input("Pattern size", "Enter pattern size:\"w,h\"")
    if d1 == false then
        return false
    end
    --print(string.sub(whs, 1, n - 1)..'\\'..string.sub(whs, n, #whs))
    change_mode()
    modes[2].set_raw_size(d1,d2)
    hud_plain('W: '..modes[2].width..', H: '..modes[2].height)
end

modes[2].set_xy_offset = function()
    local d1,d2 = modes[2].proper_input("Pattern offset", "Enter pattern offset:\"x,y\"")
    if d1 == false then
        return false
    end
    modes[2].x_offset,modes[2].y_offset = d1,d2
    modes[2].hud_alert(true)
end

modes[2].pick_key_handler = function(key)
    if (modes[2].width==0 and modes[2].height==0) then
        if key == keys["num+"] then
            modes[2].set_pattern_size()
            return false
        else
            hud_plain('Set pattern size first! (Press "+")')
            return false
        end
    end
    if key == keys["up"] then
        modes[2].ptr_ud  = restrict_ptr(modes[2].ptr_ud ,modes[2].height,-1)
    elseif key == keys["down"] then
        modes[2].ptr_ud  = restrict_ptr(modes[2].ptr_ud ,modes[2].height,1)
    elseif key == keys["left"] then
        modes[2].ptr_lr  = restrict_ptr(modes[2].ptr_lr ,modes[2].width,-1)
    elseif key == keys["right"] then
        modes[2].ptr_lr  = restrict_ptr(modes[2].ptr_lr ,modes[2].width,1)
    elseif key == keys["num+"] then
        modes[2].set_pattern_size()
        return false
    elseif key == keys["num-"] then
        modes[2].set_xy_offset()
        return false
    elseif key == keys["delete"] then
        modes[2].list[modes[2].ptr_ud][modes[2].ptr_lr] = false
    elseif key == keys["num*"] then
        modes[2].hud_alert(true)
        return false
    elseif key == keys["num/"] then
        local x,y = sim.adjustCoords(tpt.mousex,tpt.mousey)
        modes[2].pick_parts(x,y)
        hud_plain('Pattern sampled!')
        return false
    else
        return
    end
    modes[2].hud_alert()
    return false
end

modes[3].pick_key_handler = function(key)
    if key == keys["delete"] then
        if modes[3].list[modes[3].selected_number] then
            table.remove(modes[3].list,modes[3].selected_number)
            global_pked_color()
        end
    elseif key == keys["pgup"] then
        if modes[3].selected_number > 1 then
            modes[3].selected_number = modes[3].selected_number - 1
        end
    elseif key == keys["pgdn"] then
        if modes[3].selected_number < 5 and modes[3].selected_number <= #modes[3].list then
            modes[3].selected_number = modes[3].selected_number + 1
        end
    elseif key == keys["num*"] then
        --only an hud_alert
    elseif key == keys["num/"] then
        local x,y = sim.adjustCoords(tpt.mousex,tpt.mousey)
        modes[3].pick_parts(x,y)
        hud_plain('Stack sampled!')
        return false
    else
        return
    end
    modes[3].hud_alert()
    return false
end

local function pick_adv_key_hook(key, code, is_repeat, shift, ctrl, alt)
    if is_repeat then
        return
    end
    if tpt.selectedl ~= id_picker then
        return
    end
    if key == keys["home"] then
        local n = moden
        if n >= mode_max_n then
            n = 0
        else
            n = n + 1
        end
        change_mode(n)
        hud_plain('Mode '..(moden+1)..': '..modes[moden].name)
        return false
    elseif key == keys["end"] then
        if prop_vel_enabled then
            gen_prop_list(false)
            hud_plain('Velocity sampling is disabled!')
        else
            gen_prop_list(true)
            hud_plain('Velocity sampling is enabled!')
        end
        return false
    elseif key == keys["insert"] then -- insert(save&load)
        save.initialize()
        return false
    end
    return modes[moden].pick_key_handler(key)
end

event.register(event.keypress,pick_adv_key_hook)

local function pked_key_hook(key, code, is_repeat, shift, ctrl, alt)
    if is_repeat then
        return
    end
    if tpt.selectedl ~= id_picked then
        return
    end
    if key == keys["delete"] then --delete
        change_mode()
        return false
    elseif key == keys["insert"] then -- insert(save&load)
        save.initialize()
        return false
    end
end

event.register(event.keypress,pked_key_hook)

-- something related to cray, keep it
-- press alt holding "picked" to directly draw a dot
-- press ctrl will enable stacking
local function cray_bug_special_mouse(x,y,button)
    --print(cray_alt,button)
    if tpt.selectedl ~= id_picked or bit.band(event.getmodifiers(),256) == 0 or button ~= 1 then
        return
    end
    local x2,y2 = sim.adjustCoords(x,y)
    if bit.band(event.getmodifiers(),64) == 0 then
        sim.partCreate(-1,x2,y2,el_picked)
    else
        sim.partCreate(-3,x2,y2,el_picked)
    end
    return false
end

event.register(event.mousedown,cray_bug_special_mouse)

--local save = {} --see upward

save.cols,save.rows=5,20
function save.number_to_coord(num)
    num = num -1
    local cols,rows = save.cols,save.rows
    local page,numinpage = math.floor(num/(cols*rows)),num%(cols*rows)
    local col,row = math.floor(numinpage/rows),numinpage%rows
    return page,col,row
end

function save.scan_files()
    if not fs.isDirectory('./samples') then fs.makeDirectory('./samples') end
    local dir = fs.list('./samples')
    for _,item in ipairs(dir) do
        if fs.isDirectory('./samples/'..item) then
            table.remove(dir,_)
        end
    end
    modes[233].file_list = dir
end

function save.scan_color()
    if not fs.isFile('./samples/color/colors.txt') then return end
    for line in io.lines('./samples/color/colors.txt') do
        modes[233].color_data[line:split(':')[1]] = tonumber(line:split(':')[2],16)
    end
end

function save.save_color()
    if not fs.isDirectory('./samples/color') then fs.makeDirectory('./samples/color') end
    local f = io.open('./samples/color/colors.txt','w')
    for k,item in next,modes[233].color_data do
        f:write(k..':'..bit.tohex(bit.band(0xffffff,item),6)..'\n')
    end
    f:close()
end

function save.purge_color()
    local color_data_new = {}
    for _,item in ipairs(modes[233].file_list) do
        if modes[233].color_data[item] then
            color_data_new[item] = modes[233].color_data[item]
        end
    end
    modes[233].color_data = color_data_new
end

function save.refresh_color()
    save.scan_files()
    modes[233].color_data = {}
    for _,file in ipairs(modes[233].file_list) do
        if save.load_file(file) then
            local color = modes[modes[233].tosave_mode].quick_pked_color()
            modes[233].color_data[file] = color
        end
    end
    save.save_color()
    modes[233].tosave_mode = 0
    save.ret()
    change_mode(0)
end

function save.load_file(filename)
    if show_hud == nil then show_hud = true end
    local f = io.open('./samples/'..filename,'r')
    if not f then
        hud_plain('File does not exist!')
        return false
    end
    local data = f:read('*a')
    f:close()
    if not(data:sub(1,23) == 'DJY_ALL_SEEING_SAMPLER@') then
        hud_plain('Invalid file!')
        return false
    end
    data = data:sub(24,data:len())
    change_mode(tonumber(data:sub(5,6))-1)
    modes[233].tosave_mode = tonumber(data:sub(5,6))-1
    if modes[moden].serialdumps(data) then
        hud_plain('Loaded '..filename..'!')
    else
        hud_plain('Error!')
        return false
    end
    return true
end

function save.save_file(filename)
    if not fs.isDirectory('./samples') then fs.makeDirectory('./samples') end
    local f = io.open('./samples/'..filename..'.smp','w')
    f:write('DJY_ALL_SEEING_SAMPLER@'..modes[modes[233].tosave_mode].serialize())
    f:close()
    hud_plain('Sample is saved to '..filename..'.smp !')
end

function save.limit_text(text, length)
    if text:len() > length then
        return text:sub(1,length-3)..'...'
    end
    return text
end

function save.unpack_color(longint)
    if longint ~= nil then
        --print(longint,type(longint))
        return {bit.rshift(bit.band(0xff0000,longint),16),bit.rshift(bit.band(0x00ff00,longint),8),bit.rshift(bit.band(0x0000ff,longint),0)}
    else
        return {0,0,0}
    end
end

function save.draw_HUD()
    if not modes[233].file_list[modes[233].selected_file_number] then return end
    local page_to_draw = save.number_to_coord(modes[233].selected_file_number)
    local cw,ch = 100,12 --cw:cell width ch:cell height
    local text_max_length = 20 --max text length in cell
    for index,name in ipairs(modes[233].file_list) do
        local page,bc,br = save.number_to_coord(index)
        if page == page_to_draw then
            local bx,by = 16+bc*cw,67+br*ch
            local bgcolor = modes[233].color_data[name]
            graphics.fillRect(bx,by,cw,ch,0,0,0,192)
            if bgcolor then
                graphics.fillRect(bx+cw-ch+1,by+1,ch-3,ch-3,unpack(save.unpack_color(bgcolor)))
            end
            graphics.drawText(bx,by,save.limit_text(name,text_max_length), 255, 208, 16)
            if index == modes[233].selected_file_number then
                graphics.drawRect(bx-1,by-1,cw+1,ch+1, 255, 255, 255, 192)
            end
        end
    end
    local bcx = 16
    graphics.fillRect(bcx,320,600-bcx,16,0,0,0,192)
    graphics.drawText(bcx,320,"Selected sample: ", 255, 208, 16)
    bcx = bcx + tpt.textwidth("Selected sample: ")+1
    graphics.fillRect(bcx,320,ch-3,ch-3,unpack(save.unpack_color(modes[233].color_data[modes[233].file_list[modes[233].selected_file_number]])))
    bcx = bcx + ch-2
    graphics.drawText(bcx,320,save.limit_text(modes[233].file_list[modes[233].selected_file_number],100), 255, 208, 16)
    
end

--some placeholder
modes[233].pked_handler = function()
    for index in sim.parts() do
        if sim.partProperty(index,sim.FIELD_TYPE) == el_picked then
            sim.partKill(index)
        end
    end
end

--step functions for saving&loading
function save.pick_save_handler()
    if tpt.selectedl ~= id_picker then
        return
    end
    local whs = tpt.input('Save to file','Enter file name:')
    if whs == '' then
        hud_plain('File name is empty!')
        tpt.selectedl = 'DEFAULT_PT_DUST'
        return
    end
    save.save_file(whs)
    modes[233].color_data[whs..'.smp'] = modes[modes[233].tosave_mode].quick_pked_color()
    save.save_color()
    save.ret()
end

function save.pked_load_handler()
    if tpt.selectedl ~= id_picked then
        return
    end
    save.draw_HUD()
end

--key function
function save.pked_load_key(key, code, is_repeat, shift, ctrl, alt)
    if is_repeat then
        return
    end
    if tpt.selectedl ~= id_picked then
        return
    end
    if key == keys["up"] then --u
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,-1)
    elseif key == keys["down"] then --d
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,1)
    elseif key == keys["left"] then --l
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,-save.rows)
    elseif key == keys["right"] then --r
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,save.rows)
    elseif key == keys["pgup"] then --pgup
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,-save.rows*save.cols)
    elseif key == keys["pgdn"] then --pgdn
        modes[233].selected_file_number  = restrict_ptr(modes[233].selected_file_number ,#modes[233].file_list,save.rows*save.cols)
    elseif key == keys["num+"] then -- +
        save.load_file(modes[233].file_list[modes[233].selected_file_number])
        save.ret()
    elseif key == keys["num-"] then -- -
        local whs = tpt.input('Load file','Enter file name:')
        if whs == '' then
            hud_plain('File name is empty!')
            return
        end
        save.load_file(whs)
        save.ret()
    elseif key == keys["num/"] then -- /
        tpt.set_clipboard('DJY_ALL_SEEING_SAMPLER@'..modes[modes[233].tosave_mode].serialize())
        hud_plain('Sample is copied to clipboard!')
        save.ret()
    elseif key == keys["num*"] then -- *
        local data = tpt.get_clipboard()
        if not(data:sub(1,23) == 'DJY_ALL_SEEING_SAMPLER@') then
            hud_plain('Invalid clipboard data!')
            return false
        end
        data = data:sub(24,data:len())
        modes[233].tosave_mode = tonumber(data:sub(5,6))-1
        save.ret()
        if modes[moden].serialdumps(data) then
            hud_plain('Sample is pasted from clipboard!')
        else
            hud_plain('Error!')
        end
    elseif key == keys["insert"] then -- insert:return to normal mode
        save.ret()
    elseif key == keys["end"] then -- end:refresh
        save.scan_files()
        save.scan_color()
        hud_plain('Found '..#modes[233].file_list..' file(s)!')
    elseif key == keys["delete"] then -- delete
        local filename = modes[233].file_list[modes[233].selected_file_number]
        if tpt.confirm('Delete file','Are you sure that you want to delete '..filename..' ?','Delete') then
            fs.removeFile('./samples/'..filename)
        end
        save.scan_files()
        save.purge_color()
        save.save_color()
    elseif key == keys["home"] then -- home:refresh_color
        if tpt.confirm('Rescan','Are you sure that you want to rescan all the sample\'s color? You\'ll lose your current unsaved sample!','Rescan') then
            save.refresh_color()
            hud_plain('Sample colors are rescanned!')
        end
    else
        return
    end
    return false
end

function save.initialize()
    tpt.selectedl = 'DEFAULT_PT_DUST'
    modes[233].tosave_mode = moden
    moden=233
    event.unregister(event.keypress,pked_key_hook)
    event.unregister(event.keypress,pick_adv_key_hook)
    event.unregister(event.mousedown,cray_bug_special_mouse)
    event.unregister(event.mousedown,picker_hook)
    event.unregister(event.mouseup,picker_hook_up)
    
    local tt = modes[233].tooltips
    elem.property(el_picker,"Description",tt.pick)
    elem.property(el_picker,"Colour",tt.color1)
    elem.property(el_picked,"Description",tt.pked)
    elem.property(el_picked,"Colour",tt.color2)
    hud_plain(modes[233].name)
    
    save.scan_files()
    save.scan_color()
    
    event.register(event.tick,save.pick_save_handler)
    event.register(event.tick,save.pked_load_handler)
    event.register(event.keypress,save.pked_load_key)
end

function save.ret()
    tpt.selectedl = id_picked
    moden = modes[233].tosave_mode
    save_def = {
        file_list = {},
        selected_file_number = 1,
        tosave_mode = 0,
        color_data = {}
    }
    for k,v in pairs(save_def) do
        modes[233][k] = v
    end
    
    event.unregister(event.tick,save.pick_save_handler)
    event.unregister(event.tick,save.pked_load_handler)
    event.unregister(event.keypress,save.pked_load_key)
    
    local tt = modes[moden].tooltips
    elem.property(el_picker,"Description",tt.pick)
    elem.property(el_picker,"Colour",tt.color)
    elem.property(el_picked,"Description",tt.pked)
    global_pked_color()
    
    event.register(event.keypress,pked_key_hook)
    event.register(event.keypress,pick_adv_key_hook)
    event.register(event.mousedown,cray_bug_special_mouse)
    event.register(event.mousedown,picker_hook)
    event.register(event.mousedown,picker_hook)
    event.register(event.mouseup,picker_hook_up)
end

local function quick_switch_tool(key, code, is_repeat, shift, ctrl, alt)
    if is_repeat or key ~= keys["scrlck"] then
        return
    end
    if tpt.selectedl == id_picker then
        tpt.selectedl = id_picked
        hud_plain("Selected tool: ["..chars["part"].."]")
        return false
    else
        tpt.selectedl = id_picker
        hud_plain("Selected tool: ["..chars["eye"].."]")
        return false
    end
end

event.register(event.keypress,quick_switch_tool)

Description:

Changelog: