FILES ----- hobo.ttf biomes\underground\generic\underground1a.biome biomes\underground\generic\underground1b.biome biomes\underground\generic\underground1c.biome biomes\underground\generic\underground1d.biome biomes\underground\generic\underground3a.biome biomes\underground\generic\underground3b.biome biomes\underground\generic\underground3c.biome biomes\underground\generic\underground3d.biome biomes\underground\generic\underground5a.biome biomes\underground\generic\underground5b.biome biomes\underground\generic\underground5c.biome biomes\underground\generic\underground5d.biome biomes\underground\generic\bottom\rock04layer.biome biomes\underground\generic\bottom\rock12layer.biome biomes\underground\generic\bottom\rock14layer.biome biomes\underground\generic\bottom\rock15layer.biome biomes\underground\generic\bottom\rock17layer.biome biomes\underground\generic\middle\rock01layer.biome biomes\underground\generic\middle\rock02.biome biomes\underground\generic\middle\rock03.biome biomes\underground\generic\middle\rock19.biome biomes\underground\generic\middle\rock20.biome biomes\underground\generic\top\claylayer.biome biomes\underground\generic\top\drydirtlayer.biome biomes\underground\generic\top\drysandlayer.biome biomes\underground\generic\top\gravellayer.biome biomes\underground\generic\top\mudlayer.biome biomes\underground\generic\top\sandlayer.biome biomes\underground\generic\top\sandstonelayer.biome dungeons\microdungeons\randomencounter\apexunderground\apexundergroundencounter.dungeon [NEW] dungeons\microdungeons\randomencounter\floranunderground\floranclass1.png [NEW] dungeons\microdungeons\randomencounter\floranunderground\floranclass1obj.png [NEW] dungeons\microdungeons\randomencounter\floranunderground\florand1.png [NEW] dungeons\microdungeons\randomencounter\floranunderground\florand1obj.png [NEW] dungeons\microdungeons\randomencounter\floranunderground\florand2.png [NEW] dungeons\microdungeons\randomencounter\floranunderground\florand2obj.png dungeons\microdungeons\randomencounter\floranunderground\floranundergroundencounter.dungeon [NEW] dungeons\microdungeons\randomencounter\genericunderground\genericundergroundencounter.dungeon [NEW] dungeons\microdungeons\randomencounter\genericunderground\mineshaft1.png [NEW] dungeons\microdungeons\randomencounter\genericunderground\mineshaft1obj.png [NEW] dungeons\microdungeons\randomencounter\glitchunderground\ghouse1.png [NEW] dungeons\microdungeons\randomencounter\glitchunderground\ghouse1obj.png dungeons\microdungeons\randomencounter\glitchunderground\glitchundergroundencounter.dungeon [NEW] dungeons\microdungeons\randomencounter\humanunderground\humanarcadebattle.png [NEW] dungeons\microdungeons\randomencounter\humanunderground\humanarcadebattleobj.png [NEW] dungeons\microdungeons\randomencounter\humanunderground\humanundergroundencounter.dungeon [NEW] dungeons\microdungeons\randomencounter\outpostunderground\bunker1-objects.png [NEW] dungeons\microdungeons\randomencounter\outpostunderground\bunker1.png [NEW] dungeons\microdungeons\randomencounter\outpostunderground\outpostundergroundencounter.dungeon dungeons\missions\penguinmissions\penguinmission2-objects.png interface\easel\lightbutton.frames interface\easel\print.frames [NEW] interface\easel\scaninput.frames interface\easel\signstoregui.lua interface\easel\spectrumchart.png interface\easel\staticcolor.png monsters\boss\crystalboss\crystalboss.animation monsters\boss\crystalboss\idlestate.lua monsters\boss\crystalboss\crystal\crystalback.png monsters\boss\crystalboss\crystal\crystalbody.png [NEW] monsters\boss\crystalboss\crystal\crystalbossicon.png monsters\boss\crystalboss\crystal\crystaleye.png monsters\boss\crystalboss\skills\crystalbeamattack.lua monsters\boss\crystalboss\skills\crystalbeamattack.monsterskill objects\generic\torch\torch.object objects\glitch\medievaltorch\medievaltorch.object objects\mission\lunarbasebunk\lunarbasebunk.object [NEW] objects\outpost\customsign\customsign.animation [NEW] objects\outpost\customsign\customsign.lua [NEW] objects\outpost\customsign\customsign.object [NEW] objects\outpost\customsign\customsignframe.frames [NEW] objects\outpost\customsign\customsignframe.png objects\outpost\outpostlamp\outpostlamp.frames objects\outpost\outpostlamp\outpostlamp.object objects\outpost\outpostlamp\outpostlamplit.frames objects\outpost\outpostlight\outpostlight.frames objects\outpost\outpostlight\outpostlight.object objects\outpost\outpostlight\outpostlight.png [NEW] objects\outpost\outpostlight\outpostlightlit.frames [NEW] objects\outpost\outpostlight\outpostlightlit.png [NEW] objects\outpost\outpostmonitor\outpostmonitor.animation objects\outpost\outpostmonitor\outpostmonitor.frames objects\outpost\outpostmonitor\outpostmonitor.object objects\outpost\outpostmonitor\outpostmonitor.png objects\outpost\outpostmonitor\outpostmonitorlit.frames objects\outpost\outpostmonitor\outpostmonitorlit.png [NEW] objects\outpost\outpostsmallmonitor\outpostsmallmonitor.animation objects\outpost\outpostsmallmonitor\outpostsmallmonitor.frames objects\outpost\outpostsmallmonitor\outpostsmallmonitor.object objects\outpost\outpostsmallmonitor\outpostsmallmonitor.png objects\outpost\outpostsmallmonitor\outpostsmallmonitorlit.frames objects\outpost\outpostsmallmonitor\outpostsmallmonitorlit.png objects\outpost\signstore\signdispenser.lua objects\outpost\signstore\signstoreobject.lua [NEW] projectiles\boss\crystalboss\crystalbeamdamage.projectile projectiles\explosions\coconutexplosion\coconutbreak.config projectiles\explosions\healingexplosion\healcloud.config projectiles\explosions\poisonsmoke\poisonsmoke.config projectiles\minibiomelegendaries\sporecloud\multisporecloud.projectile projectiles\minibiomelegendaries\sporecloudx\multisporecloudx.projectile [NEW] sfx\projectiles\fire_out_louder.wav treasure\common.treasurepools DIFFS ----- hobo.ttf Files C:\Program Files (x86)\Steam\SteamApps\common\Starbound\__assets\hobo.ttf and C:\Program Files (x86)\Steam\SteamApps\common\Starbound\_assets\hobo.ttf differ (KAWA'S NOTE: They added Cyrillic -- U+0400 to U+0527) biomes\underground\generic\underground1a.biome 142c142 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground1b.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground1c.biome 142c142 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground1d.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground3a.biome 142c142 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground3b.biome 142c142 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground3c.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground3d.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground5a.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground5b.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground5c.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\underground5d.biome 130c130 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\bottom\rock04layer.biome 154c154 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\bottom\rock12layer.biome 155c155 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\bottom\rock14layer.biome 155c155 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\bottom\rock15layer.biome 155c155 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\bottom\rock17layer.biome 155c155 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\middle\rock01layer.biome 157c157 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\middle\rock02.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\middle\rock03.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\middle\rock19.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\middle\rock20.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\claylayer.biome 158c158 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\drydirtlayer.biome 158c158 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\drysandlayer.biome 157c157 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\gravellayer.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\mudlayer.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\sandlayer.biome 156c156 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] biomes\underground\generic\top\sandstonelayer.biome 157c157 < "microdungeons" : [ "genericunderground", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] --- > "microdungeons" : [ "genericundergroundencounter", "apexundergroundencounter", "avianundergroundencounter", "floranundergroundencounter", "glitchundergroundencounter", "humanundergroundencounter", "outpostundergroundencounter" ] dungeons\microdungeons\randomencounter\apexunderground\apexundergroundencounter.dungeon 918c918 < "brush" : [ [ "clear" ], [ "object", "techchest", { "direction" : "left", "parameters" : { "treasurePools" : [ "techTreasure" ] } } ] ] --- > "brush" : [ [ "clear" ], [ "object", "techchest", { "direction" : "left", "parameters" : { "treasurePools" : [ "microdungeonTechTreasure" ] } } ] ] 924c924 < "brush" : [ [ "clear" ], [ "object", "techchest", { "direction" : "right", "parameters" : { "treasurePools" : [ "techTreasure" ] } } ] ] --- > "brush" : [ [ "clear" ], [ "object", "techchest", { "direction" : "right", "parameters" : { "treasurePools" : [ "microdungeonTechTreasure" ] } } ] ] dungeons\microdungeons\randomencounter\floranunderground\floranundergroundencounter.dungeon 7c7 < "anchor" : [ "chamber1" ], --- > "anchor" : [ "chamber1", "florand1", "floranclass1", "florand2" ], 2527a2528,2545 > }, > > { > "name" : "florand1", > "rules" : [ ], > "def" : [ "image", [ "florand1.png", "florand1obj.png" ] ] > }, > > { > "name" : "floranclass1", > "rules" : [ ], > "def" : [ "image", [ "floranclass1.png", "floranclass1obj.png" ] ] > }, > > { > "name" : "florand2", > "rules" : [ ], > "def" : [ "image", [ "florand2.png", "florand2obj.png" ] ] dungeons\microdungeons\randomencounter\glitchunderground\glitchundergroundencounter.dungeon 7c7 < "anchor" : [ "sewer1", "sewer2", "sewer3", "sewer4", "traproom1", "traproom2", "traproom3" ], --- > "anchor" : [ "ghouse1", "sewer1", "sewer2", "sewer3", "sewer4", "traproom1", "traproom2", "traproom3" ], 2449a2450,2456 > > { > "name" : "ghouse1", > "rules" : [ ], > "def" : [ "image", [ "ghouse1.png", "ghouse1obj.png" ] ] > }, > interface\easel\lightbutton.frames 6c6 < [ "on", "highlight", "off" ] --- > [ "off", "highlight", "on" ] interface\easel\print.frames 3c3 < "size" : [24, 8], --- > "size" : [54, 14], interface\easel\signstoregui.lua 6,150c6,140 < --I'd make this more unique with the world name, but the seem to have removed world.info() < --Using world.get/set properties to store persistent data (sign state and templates) between sessions < --I suppose if an outpost is going to do this stuff, the storage process will be much streamlined < uniqueEaselIdentifier = "Easel@" .. world.entityPosition(console.sourceEntity())[1] .. world.entityPosition(console.sourceEntity())[2] < if world.getProperty(uniqueEaselIdentifier.."storage") ~= nil then < storage = world.getProperty(uniqueEaselIdentifier.."storage") < --world.logInfo("World Storage Found: %s", world.getProperty(uniqueEaselIdentifier.."storage")) < templates = world.getProperty(uniqueEaselIdentifier.."templates") < --world.logInfo("World Templates Found: %s", world.getProperty(uniqueEaselIdentifier.."templates")) < else < storage = {} < templates = {} < end < < --all "storage." and "template." variables are supposed to be permanent, while "self." or un-prefixed variables are session-specific < < templates["fromContainer"] = nil < storage.currentFrame = storage.currentFrame or 1 < if storage.signPixels == nil then < storage.signPixels = {{}} < for x=1,32 do < storage.signPixels[storage.currentFrame][x] = {} < for y=1,8 do < storage.signPixels[storage.currentFrame][x][y] = 0 < end < end < end < storage.signName = storage.signName or "Sign" < storage.signDirectiveStrings = storage.signDirectiveStrings or {} < storage.frameTypes = {{"black", "000000FF", "000000FF"} , {"lightwood", "B75E2AFF", "BC6B40FF" },{"darkwood" ,"441A00FF", "2D1100FF"},{"darkmetal" ,"404040FF","606060FF"},{"none" ,"00000000", "00000000"}} < storage.backingTypes = {"blank" , "parchment", "blackboard", "glass", "none", "hazard"} < --Anchors and Offsets. All rendered parts of the ui are given their positions here, with a personal offset (scanvasButtonOffsets) < --applied to a more general anchor. Makes it easier to bundle and shift bits around. < < --Anchors are pure {x,y} < canvasAnchors = { < ["templates"] = {94, 171}, < ["main"] = {70,10}, < ["color"] = {294,8}, < ["colorWindow"] = {15,25}, < ["errorWindow"] = {35,50}, < ["inputWindow"] = {35,50} < } < canvasButtonOffsets = { < --"S:__" buttons are statics, ignored for button finding, just there for a consistent point-of-access when moving stuff < --The others have {x, y, x+xsize-1, y+ysize-1} < --Why -1? just because I use <= in the button detection. either way some parts owuld need offsets. < ["S:digit11"] = {"main", 158, 6}, < ["S:digit12"] = {"main", 162, 6}, < ["S:digit21"] = {"main", 158, -6}, < ["S:digit22"] = {"main", 162, -6}, < ["S:currentIcon"] = {"main", -90, 33}, < ["S:templates"] = {"templates", -84, -39}, < ["S:signName"] = {"templates", -59, -22}, < ["pixelPress"] = {"main", 12, 30, 12+191, 30+47}, < ["framePress"] = {"main", 0, 18, 0+215, 18+71}, < ["backingLeft"] = {"main", 232, 48, 216+11, 48+23}, < ["backingRight"] = {"main", 264, 48, 264+11, 48+23}, < ["frameLeft"] = {"main", 135, -2, 135+11, -2+23}, < ["frameRight"] = {"main", 172, -2, 170+11, -2+23}, < ["frameAdd"] = {"main", 148, 5, 148+11, 5+11}, < ["frameDelete"] = {"main", 148, -7, 148+11, -7+11}, < ["shiftLeft"] = {"main", -5, 48, 6, 48+10}, < ["shiftUp"] = {"main", 107, 83, 107+11, 83+10}, < ["shiftRight"] = {"main", 209, 48, 209+11, 48+10}, < ["shiftDown"] = {"main", 107, 13, 107+11, 13+10}, < --["iconGrab"] = {"main", -96, 18, -96+35, 18+11}, < ["clearPress"] = {"templates", 186, -25, 186+35, -25+11}, < ["printPress"] = {"templates", 146, -25, 146+35, -25+11}, < ["undoPress"] = {"templates", 146, -38, 146+35, -38+11}, < ["nameInput"] = {"templates", -79, -37, -79+11, -37+23}, < ["templateSlotCopy"] = {"templates", -66, 0, -66+29, 0+29}, < ["S:toolTip"] = {"templates", -75, 44}, < ["S:colorStatics"] = {"color", 9, 62}, --0 84 < ["S:modifierStatics"] = {"color", 180, 0}, --0 48 < ["S:alphaNumber"] = {"color", 115, 16},-- 25 29 < ["S:colorDisplay"] = {"color", 14, 74, 44, 82}, --19 102 52 113 < ["S:miniBacking"] = {"color", 15, 50}, < ["S:mainStatics"] = {"color", 9, 40}, < ["colorInput"] = {"color", 14, 74, 44, 82}, --6 96 +11 +23 < ["pickToggle"] = {"color", 9, 0, 9+18, 0+18}, --6 60 +23 +23 < ["fillToggle"] = {"color", 31, 0, 31+18, 0+18}, --30 60 +23 +23 < ["isWired"] = {"color", 9, 20, 9+18, 20+18}, < ["lightSelect"] = {"color", 31, 20, 31+18, 20+18}, < ["S:spectrumWindow"] = {"colorWindow" , 0, 0}, < ["spectrumPress"] = {"colorWindow", 21, 25, 21+315, 25+109}, < ["S:inputWindow"] = {"inputWindow", 0, 0}, < ["S:inputPrompt"] = {"inputWindow", 33, 83}, < ["S:inputData"] = {"inputWindow", 33, 53}, < ["S:errorWindow"] = {"errorWindow", 0, 0}, < ["S:errorPrompt1"] = {"errorWindow", 15, 73}, < ["S:errorPrompt2"] = {"errorWindow", 15, 52} < } < --I tired to have some consistent button naming < storage.buttonStates = storage.buttonStates or {frameAdd = "normal", frameDelete = "grayed", backingLeft = "normal", backingRight = "normal", < frameLeft = "normal", frameRight = "normal", shiftRight = "normal", shiftLeft = "normal", < shiftUp = "normal", shiftDown = "normal", clearPress = "normal", < isWired = "off", printPress = "normal", iconGrab = "normal", undoPress = "grayed", < colorInput = "normal", nameInput = "normal", pickToggle = "off", fillToggle = "off", < templateSlotCopy = "normal", lightSelect = "off"} < --yes, paintColor contains the alpha, but since the user edits them independently this is useful < storage.paintColor = storage.paintColor or "000000FF" < storage.paintAlpha = storage.paintAlpha or 255 < < --I hate some parts of lua. Using "pairs()" to copy tables is great, but I think it has issue when a table is indexed by both numbers < --and strings. Hard to tell, but I'm pretty sure it keeps converting between the two. Very anoying since I have to use that function < --to store and retrieve data. < -- < --Well, after some changes it might not be necessary anymore, but that's why I've taken pains to index lightData buy "f#" instead of "#" everywhere. < storage.lightData = storage.lightData or {} < storage.frameTypesIndex = storage.frameTypesIndex or 1 < storage.backingTypesIndex = storage.backingTypesIndex or 1 < storage.isWired = storage.isWired or false < self.currentCursorModifier = nil < storage.currentPixelValueTo = storage.currentPixelValueTo or 1 < storage.currentIcon = storage.currentIcon or "customicons.png:blank-black" < self.undoStack = {} < self.lookingForSignDrop = 0 < dropSpot = world.entityPosition(console.sourceEntity()) < < --storage.buttonStates["undoPress"] = "grayed" storage.buttonStates["pickToggle"] = "off" storage.buttonStates["fillToggle"] = "off" < < local matchingCabinetList = world.objectQuery({world.entityPosition(console.sourceEntity())[1]-4,world.entityPosition(console.sourceEntity())[2]},1) < for i,j in ipairs(matchingCabinetList) do < if world.entityName(j) == "signdispenser" then self.matchingCabinet = j end < end < if self.matchingCabinet == nil then console.dismiss() end < --As a client-side script, I can't get returns from world.callScriptedEntity. I like to use this item drop method to get information from objects - here the sign in the input slot. < requestSignDrop() < --A bunch of transient states < shiftHeld = false < capsLock = false < self.blinking = {false, 0} < self.undoSubStack = {"reverseStroke"} < self.toolTip = "" < --Error format: {timer, "MessageLineOne", "MessageLineTwo"} < self.thrownError = nil < --Input format: {"Message", enteredSoFar, type} < self.inputBoxMode = nil < self.showSpectrumCursor = {0, {0,0}} < self.clickplease = -1 < self.colorSelectBox = false < < --the object needs to know these things too, to persist through destruction < world.callScriptedEntity(console.sourceEntity(), "storeData", storage, templates) --- > --I'd make this more unique with the world name, but the seem to have removed world.info() > --Using world.get/set properties to store persistent data (sign state and templates) between sessions > --I suppose if an outpost is going to do this stuff, the storage process will be much streamlined > uniqueEaselIdentifier = "Easel@" .. world.entityPosition(console.sourceEntity())[1] .. world.entityPosition(console.sourceEntity())[2] > if world.getProperty(uniqueEaselIdentifier.."storage") ~= nil then > storage = world.getProperty(uniqueEaselIdentifier.."storage") > --world.logInfo("World Storage Found: %s", world.getProperty(uniqueEaselIdentifier.."storage")) > templates = world.getProperty(uniqueEaselIdentifier.."templates") > --world.logInfo("World Templates Found: %s", world.getProperty(uniqueEaselIdentifier.."templates")) > else > storage = {} > templates = {} > end > > --all "storage." and "template." variables are supposed to be permanent, while "self." or un-prefixed variables are session-specific > > templates["fromContainer"] = nil > storage.currentFrame = storage.currentFrame or 1 > if storage.signPixels == nil then > storage.signPixels = {{}} > for x=1,32 do > storage.signPixels[storage.currentFrame][x] = {} > for y=1,8 do > storage.signPixels[storage.currentFrame][x][y] = 0 > end > end > end > storage.signName = storage.signName or "Sign" > storage.signDirectiveStrings = storage.signDirectiveStrings or {} > storage.frameTypes = {{"black", "000000FF", "000000FF"} , {"lightwood", "B75E2AFF", "BC6B40FF" },{"darkwood" ,"441A00FF", "2D1100FF"},{"darkmetal" ,"404040FF","606060FF"},{"none" ,"00000000", "00000000"}} > storage.backingTypes = {"blank" , "parchment", "blackboard", "glass", "none", "hazard"} > --Anchors and Offsets. All rendered parts of the ui are given their positions here, with a personal offset (scanvasButtonOffsets) > --applied to a more general anchor. Makes it easier to bundle and shift bits around. > > --Anchors are pure {x,y} > canvasAnchors = { > ["templates"] = {7, 8}, > ["main"] = {70,10}, > ["color"] = {294,8}, > ["colorWindow"] = {25,5}, > ["errorWindow"] = {25,5} > } > canvasButtonOffsets = { > --"S:__" buttons are statics, ignored for button finding, just there for a consistent point-of-access when moving stuff > --The others have {x, y, x+xsize-1, y+ysize-1} > --Why -1? just because I use <= in the button detection. either way some parts owuld need offsets. > ["S:digit11"] = {"main", 158, 6}, > ["S:digit12"] = {"main", 162, 6}, > ["S:digit21"] = {"main", 158, -6}, > ["S:digit22"] = {"main", 162, -6}, > ["pixelPress"] = {"main", 12, 30, 12+191, 30+47}, > ["framePress"] = {"main", 0, 18, 0+215, 18+71}, > ["backingLeft"] = {"main", 232, 48, 216+11, 48+23}, > ["backingRight"] = {"main", 264, 48, 264+11, 48+23}, > ["frameLeft"] = {"main", 135, -2, 135+11, -2+23}, > ["frameRight"] = {"main", 172, -2, 170+11, -2+23}, > ["frameAdd"] = {"main", 148, 5, 148+11, 5+11}, > ["frameDelete"] = {"main", 148, -7, 148+11, -7+11}, > ["shiftLeft"] = {"main", -5, 48, 6, 48+10}, > ["shiftUp"] = {"main", 107, 83, 107+11, 83+10}, > ["shiftRight"] = {"main", 209, 48, 209+11, 48+10}, > ["shiftDown"] = {"main", 107, 13, 107+11, 13+10}, > ["templateSlotCopy"] = {"templates", 74, -4, 74+17, -4+17}, > ["templateSlotScanButton"] = {"templates", 90, -2, 90+57, -2+14}, > --["iconGrab"] = {"main", -96, 18, -96+35, 18+11}, > ["clearPress"] = {"templates", 0, 70, 0+54, 70+14}, > ["printPress"] = {"templates", 0, 47, 0+54, 47+14}, > ["undoPress"] = {"templates", 0, 24, 0+54, 24+14}, > ["S:colorStatics"] = {"color", 9, 62}, --0 84 > ["S:alphaNumber"] = {"color", 115, 16},-- 25 29 > ["S:colorDisplay"] = {"color", 14, 74, 43, 81}, --19 102 52 113 > ["S:miniBacking"] = {"color", 15, 50}, > ["S:mainStatics"] = {"color", 9, 40}, > ["colorInput"] = {"color", 14, 74, 44, 82}, --6 96 +11 +23 > ["pickToggle"] = {"color", 9, 0, 9+18, 0+18}, --6 60 +23 +23 > ["fillToggle"] = {"color", 31, 0, 31+18, 0+18}, --30 60 +23 +23 > ["isWired"] = {"color", 9, 20, 9+18, 20+18}, > ["lightSelect"] = {"color", 31, 20, 31+18, 20+18}, > ["S:spectrumWindow"] = {"colorWindow" , 0, 0}, > ["spectrumPress"] = {"colorWindow", 21, 25, 21+158, 25+55}, > ["S:errorWindow"] = {"errorWindow", 0, 0}, > ["S:errorPrompt1"] = {"errorWindow", 15, 73}, > ["S:errorPrompt2"] = {"errorWindow", 15, 52} > } > --I tired to have some consistent button naming > storage.buttonStates = storage.buttonStates or {frameAdd = "normal", frameDelete = "grayed", backingLeft = "normal", backingRight = "normal", > frameLeft = "normal", frameRight = "normal", shiftRight = "normal", shiftLeft = "normal", > shiftUp = "normal", shiftDown = "normal", clearPress = "normal", templateSlotScanButton = "normal", > isWired = "off", printPress = "normal", iconGrab = "normal", undoPress = "normal", > colorInput = "normal", pickToggle = "off", fillToggle = "off", > templateSlotCopy = "normal", lightSelect = "off"} > --yes, paintColor contains the alpha, but since the user edits them independently this is useful > storage.paintColor = storage.paintColor or "000000FF" > storage.paintAlpha = storage.paintAlpha or 255 > > --I hate some parts of lua. Using "pairs()" to copy tables is great, but I think it has issue when a table is indexed by both numbers > --and strings. Hard to tell, but I'm pretty sure it keeps converting between the two. Very anoying since I have to use that function > --to store and retrieve data. > -- > --Well, after some changes it might not be necessary anymore, but that's why I've taken pains to index lightData buy "f#" instead of "#" everywhere. > storage.lightData = storage.lightData or {} > storage.frameTypesIndex = storage.frameTypesIndex or 1 > storage.backingTypesIndex = storage.backingTypesIndex or 1 > storage.isWired = storage.isWired or false > self.currentCursorModifier = nil > storage.currentPixelValueTo = storage.currentPixelValueTo or 1 > storage.currentIcon = storage.currentIcon or "customicons.png:blank-black" > self.undoStack = {} > self.lookingForSignDrop = 0 > dropSpot = world.entityPosition(console.sourceEntity()) > > --storage.buttonStates["undoPress"] = "grayed" storage.buttonStates["pickToggle"] = "off" storage.buttonStates["fillToggle"] = "off" > > local matchingCabinetList = world.objectQuery({world.entityPosition(console.sourceEntity())[1]+7,world.entityPosition(console.sourceEntity())[2]},1) > for i,j in ipairs(matchingCabinetList) do > if world.entityName(j) == "signdispenser" then self.matchingCabinet = j end > end > if self.matchingCabinet == nil then console.dismiss() end > --As a client-side script, I can't get returns from world.callScriptedEntity. I like to use this item drop method to get information from objects - here the sign in the input slot. > requestSignDrop() > --A bunch of transient states > shiftHeld = false > capsLock = false > self.blinking = {false, 0} > self.undoSubStack = {"reverseStroke"} > --Error format: {timer, "MessageLineOne", "MessageLineTwo"} > self.thrownError = nil > --Input format: {"Message", enteredSoFar, type} > self.inputBoxMode = nil > self.showSpectrumCursor = {0, {0,0}} > self.clickplease = -1 > self.colorSelectBox = false > > --the object needs to know these things too, to persist through destruction > world.callScriptedEntity(console.sourceEntity(), "storeData", storage, templates) 154,218c144,205 < local toPointer = console.canvasMousePosition() < --keeps looking for a while for that sign drop < if self.lookingForSignDrop > 0 then < lookForTemplateSign(dropSpot) < end < --here click-and-drag is handled for the relevant actions < --oldPointer updates, byt oldButton sticks with the intial click < if storage.oldPointer ~= nil then < if storage.oldButton == "pixelPress" then < if detectButton(toPointer) == "pixelPress" then < if (storage.oldPointer[1] ~= toPointer[1] or storage.oldPointer[2] ~= toPointer[2]) then < setPixel(detectPixel(toPointer), storage.currentPixelValueTo) < end < end < elseif storage.oldButton == "spectrumPress" then < if detectButton(toPointer) == "spectrumPress" then < setSpectrum(toPointer, 1) < end < end < storage.oldPointer = toPointer < end < < if self.clickplease == 0 then < --executing button presses < self.clickplease = -1 < if storage.oldPointer ~= nil and detectButton(storage.oldPointer) ~= nil then < if storage.oldPointer ~= nil and storage.oldButton == detectButton(storage.oldPointer) then < doButton(storage.oldButton, toPointer) < elseif storage.oldButton == "pickPixel" and detectButton(storage.oldPointer) == "pixelPress" then < doButton("pickPixel", toPointer) < elseif storage.oldButton == "fillPixel" and detectButton(storage.oldPointer) == "pixelPress" then < doButton("fillPixel", toPointer) < end < end < --un-highlight buttons < if storage.buttonStates[storage.oldButton] == "highlight" then < storage.buttonStates[storage.oldButton] = "normal" < end < < storage.oldPointer = nil < storage.oldButton = nil < --the undo sub-stack is specifically to handle multi-change "brush strokes" < if #self.undoSubStack ~= 1 then < pushToUndoStack(self.undoSubStack) < end < if storage.oldColor ~= nil then < storage.paintColor = storage.oldColor < storage.oldColor = nil < end < self.undoSubStack = {"reverseStroke"} < updateButtonStates() < --update the persistent storage < world.setProperty(uniqueEaselIdentifier.."storage", tablecopy(storage)) < world.setProperty(uniqueEaselIdentifier.."templates", tablecopy(templates)) < world.callScriptedEntity(console.sourceEntity(), "storeData", storage, templates) < end < if self.thrownError == nil and self.inputBoxMode == nil then < updateToolTip(toPointer) < end < < --update the sign's icon < local wireString = "" < local containerString = "" < if storage.buttonStates["isWired"] == "on" then wireString = "-wired" end < storage.currentIcon = "customicons.png:"..storage.backingTypes[storage.backingTypesIndex].."-"..storage.frameTypes[storage.frameTypesIndex][1]..wireString..containerString --- > local toPointer = console.canvasMousePosition() > --keeps looking for a while for that sign drop > if self.lookingForSignDrop > 0 then > lookForTemplateSign(dropSpot) > end > --here click-and-drag is handled for the relevant actions > --oldPointer updates, byt oldButton sticks with the intial click > if storage.oldPointer ~= nil then > if storage.oldButton == "pixelPress" then > if detectButton(toPointer) == "pixelPress" then > if (storage.oldPointer[1] ~= toPointer[1] or storage.oldPointer[2] ~= toPointer[2]) then > setPixel(detectPixel(toPointer), storage.currentPixelValueTo) > end > end > elseif storage.oldButton == "spectrumPress" then > if detectButton(toPointer) == "spectrumPress" then > setSpectrum(toPointer, 1) > end > end > storage.oldPointer = toPointer > end > > if self.clickplease == 0 then > --executing button presses > self.clickplease = -1 > if storage.oldPointer ~= nil and detectButton(storage.oldPointer) ~= nil then > if storage.oldPointer ~= nil and storage.oldButton == detectButton(storage.oldPointer) then > doButton(storage.oldButton, toPointer) > elseif storage.oldButton == "pickPixel" and detectButton(storage.oldPointer) == "pixelPress" then > doButton("pickPixel", toPointer) > elseif storage.oldButton == "fillPixel" and detectButton(storage.oldPointer) == "pixelPress" then > doButton("fillPixel", toPointer) > end > end > --un-highlight buttons > if storage.buttonStates[storage.oldButton] == "highlight" then > storage.buttonStates[storage.oldButton] = "normal" > end > > storage.oldPointer = nil > storage.oldButton = nil > --the undo sub-stack is specifically to handle multi-change "brush strokes" > if #self.undoSubStack ~= 1 then > pushToUndoStack(self.undoSubStack) > end > if storage.oldColor ~= nil then > storage.paintColor = storage.oldColor > storage.oldColor = nil > end > self.undoSubStack = {"reverseStroke"} > updateButtonStates() > --update the persistent storage > world.setProperty(uniqueEaselIdentifier.."storage", tablecopy(storage)) > world.setProperty(uniqueEaselIdentifier.."templates", tablecopy(templates)) > world.callScriptedEntity(console.sourceEntity(), "storeData", storage, templates) > end > > --update the sign's icon > local wireString = "" > local containerString = "" > if storage.buttonStates["isWired"] == "on" then wireString = "-wired" end > storage.currentIcon = "customicons.png:"..storage.backingTypes[storage.backingTypesIndex].."-"..storage.frameTypes[storage.frameTypesIndex][1]..wireString..containerString 221c208 < drawSignCanvas() --- > drawSignCanvas() 225,255c212,242 < if self.thrownError == nil and self.inputBoxMode == nil then --message boxes block input < if isButtonDown and (button == 1 or button == 3) then --middle mouse button isn't even a real mouse button man < --world.logInfo("Click @ %s", position) < --some buttons need to start doing stuff on mouse down, so they start executing changes starts here < if storage.oldPointer == nil then < storage.oldPointer = position < storage.oldButton = detectButton(storage.oldPointer) < if storage.oldButton == "pixelPress" then < if self.currentCursorModifier == nil then < if button == 1 then --left click to draw < storage.currentPixelValueTo = storage.paintColor < elseif button == 3 then --right click to erase < storage.currentPixelValueTo = 0 < end < setPixel(detectPixel(storage.oldPointer), storage.currentPixelValueTo) < else < storage.oldButton = self.currentCursorModifier < end < elseif storage.oldButton == "spectrumPress" then < storage.oldColor = storage.paintColor < setSpectrum(position, 1) < elseif storage.oldButton == nil or storage.buttonStates[storage.oldButton] == "grayed" then < storage.oldButton = nil < else < storage.buttonStates[storage.oldButton] = "highlight" < end < end < elseif isButtonDown == false and (button == 1 or button == 3) then < self.clickplease = 0 < end < end --- > if self.thrownError == nil and self.inputBoxMode == nil then --message boxes block input > if isButtonDown and (button == 1 or button == 3) then --middle mouse button isn't even a real mouse button man > --world.logInfo("Click @ %s", position) > --some buttons need to start doing stuff on mouse down, so they start executing changes starts here > if storage.oldPointer == nil then > storage.oldPointer = position > storage.oldButton = detectButton(storage.oldPointer) > if storage.oldButton == "pixelPress" then > if self.currentCursorModifier == nil then > if button == 1 then --left click to draw > storage.currentPixelValueTo = storage.paintColor > elseif button == 3 then --right click to erase > storage.currentPixelValueTo = 0 > end > setPixel(detectPixel(storage.oldPointer), storage.currentPixelValueTo) > else > storage.oldButton = self.currentCursorModifier > end > elseif storage.oldButton == "spectrumPress" then > storage.oldColor = storage.paintColor > setSpectrum(position, 1) > elseif storage.oldButton == nil or storage.buttonStates[storage.oldButton] == "grayed" then > storage.oldButton = nil > else > storage.buttonStates[storage.oldButton] = "highlight" > end > end > elseif isButtonDown == false and (button == 1 or button == 3) then > self.clickplease = 0 > end > end 259,277c246,264 < local keyString = nil < --some askii parsing mostly < if 33<=key and key<=126 then keyString = string.char(key) else keyString = keyCodes[key] end < if (shiftHeld or capsLock) and shiftHeld ~= capsLock then < if 97<= key and key <=122 then < keyString = string.char(key - 32) < elseif keyCodes[key] ~= nil then < keySring = keyCodes[key] < else < keyString = shiftKeyCodes[key] < end < else < if 33<=key and key<=126 then < keyString = string.char(key) < else < keyString = keyCodes[key] < end < end < --- > local keyString = nil > --some askii parsing mostly > if 33<=key and key<=126 then keyString = string.char(key) else keyString = keyCodes[key] end > if (shiftHeld or capsLock) and shiftHeld ~= capsLock then > if 97<= key and key <=122 then > keyString = string.char(key - 32) > elseif keyCodes[key] ~= nil then > keySring = keyCodes[key] > else > keyString = shiftKeyCodes[key] > end > else > if 33<=key and key<=126 then > keyString = string.char(key) > else > keyString = keyCodes[key] > end > end > 279,365c266,305 < if keyString == "shift" then < shiftHeld = true < elseif keyString == "capslock" then < if capsLock then capsLock = false else capsLock = true end < end < else < if keyString == "shift" then < shiftHeld = false < end < keyString = nil < end < < if self.thrownError ~= nil then < if keyString == "enter" then < self.thrownError = nil < end < keyString = nil < end < < if self.inputBoxMode ~= nil and keyString ~= nil then < if keyString == "enter" then < assignInputString(self.inputBoxMode[3], self.inputBoxMode[2]) < self.inputBoxMode = nil < elseif keyString == "backspace" then < if self.inputBoxMode[2] ~= "" then self.inputBoxMode[2] = string.sub(self.inputBoxMode[2], 1, -2) end < elseif keyString == "space" and string.len(self.inputBoxMode[2]) < 30 then < self.inputBoxMode[2] = self.inputBoxMode[2].." " < elseif string.len(keyString) == 1 and string.len(self.inputBoxMode[2]) < 30 then < self.inputBoxMode[2] = self.inputBoxMode[2]..keyString < end < keyString = nil < end < < if self.colorSelectBox then < if keyString == "enter" then < self.colorSelectBox = false < self.showSpectrumCursor[1] = 0 < end < keyString = nil < end < end < < function updateToolTip(position) < local blankTip = true < local button = detectButton(position) < if button ~= nil then < --some tool-tips are state-dependent, so they're addressed individually here < if string.len(button) > 11 and string.sub(button, 1, 12) == "templateSlot" then < local templateIndex = string.sub(button, 13) < if string.len(templateIndex) == 1 then < templateIndex = "slot"..templateIndex < if templates[templateIndex] ~= nil then < self.toolTip = "Load from Slot "..string.sub(templateIndex,-1)..": \""..(templates[templateIndex].signName or "*MISSING NAME").."\"" < blankTip = false < end < else < templateIndex = "fromContainer" < if templates[templateIndex] ~= nil then < self.toolTip = "Load from Input Slot: \""..(templates[templateIndex].signName or "*MISSING NAME").."\"" < blankTip = false < end < end < elseif string.len(button) > 11 and string.sub(button, 1, 12) == "templateSave" then < local templateIndex = "slot"..string.sub(button, -1) < self.toolTip = "Save \""..storage.signName.."\" to Slot "..string.sub(templateIndex,-1) < blankTip=false < elseif button == "pixelPress" then < if self.currentCursorModifier == "pickPixel" then < self.toolTip = "[Left Click] to take color" < elseif self.currentCursorModifier == "fillPixel" then < self.toolTip = "[Left Click] to fill" < else < self.toolTip = "[Left Click] to draw, [Right Click] to erase" < end < blankTip = false < elseif button == "undoPress" then < if #self.undoStack > 0 then < self.toolTip = "Undo previous actions ("..(undoTips[self.undoStack[#self.undoStack][1]] or "MISSING")..")" < blankTip = false < end < else < --most come from the array in customeasel-data.lua < self.toolTip = toolTips[button] or "*MISSING TOOLTIP*" < blankTip = false < end < end < if blankTip then self.toolTip = "" end --- > if keyString == "shift" then > shiftHeld = true > elseif keyString == "capslock" then > if capsLock then capsLock = false else capsLock = true end > end > else > if keyString == "shift" then > shiftHeld = false > end > keyString = nil > end > > if self.thrownError ~= nil then > if keyString == "enter" then > self.thrownError = nil > end > keyString = nil > end > > if self.inputBoxMode ~= nil and keyString ~= nil then > if keyString == "enter" then > assignInputString(self.inputBoxMode[3], self.inputBoxMode[2]) > self.inputBoxMode = nil > elseif keyString == "backspace" then > if self.inputBoxMode[2] ~= "" then self.inputBoxMode[2] = string.sub(self.inputBoxMode[2], 1, -2) end > elseif keyString == "space" and string.len(self.inputBoxMode[2]) < 30 then > self.inputBoxMode[2] = self.inputBoxMode[2].." " > elseif string.len(keyString) == 1 and string.len(self.inputBoxMode[2]) < 30 then > self.inputBoxMode[2] = self.inputBoxMode[2]..keyString > end > keyString = nil > end > > if self.colorSelectBox then > if keyString == "enter" then > self.colorSelectBox = false > self.showSpectrumCursor[1] = 0 > end > keyString = nil > end 367a308 > 369,476c310,398 < if storage.currentFrame > #storage.signPixels then storage.currentFrame = #storage.signPixels end < < --drawing all the bits, with relevant data dependencies < --------------- < --Main Anchor-- < --------------- < console.canvasDrawImage("/interface/easel/staticpanels.png", buttonPosition("S:mainStatics"), 1) < --console.canvasDrawImage("/interface/easel/icongrab.png:"..storage.buttonStates["iconGrab"],buttonPosition("iconGrab"), 1) < console.canvasDrawImage("/interface/easel/signbacking.png:"..storage.backingTypes[storage.backingTypesIndex], buttonPosition("pixelPress"), 1.5) < console.canvasDrawImage("/interface/easel/signframe.png:"..storage.frameTypes[storage.frameTypesIndex][1], buttonPosition("framePress"), 1.5) < console.canvasDrawImage("/interface/easel/"..storage.currentIcon, buttonPosition("S:currentIcon"), 1) --(-6.5,4.75) < console.canvasDrawImage("/interface/easel/minisignbacking.png:"..storage.backingTypes[storage.backingTypesIndex], buttonPosition("S:miniBacking"), 1) --(20,6.5) < console.canvasDrawImage("/interface/easel/scrollleft.png:"..storage.buttonStates["backingLeft"], buttonPosition("backingLeft"), 1) < console.canvasDrawImage("/interface/easel/scrollright.png:"..storage.buttonStates["backingRight"], buttonPosition("backingRight"), 1) < console.canvasDrawImage("/interface/easel/scrollleft.png:"..storage.buttonStates["frameLeft"], buttonPosition("frameLeft"), 1) < console.canvasDrawImage("/interface/easel/scrollright.png:"..storage.buttonStates["frameRight"], buttonPosition("frameRight"), 1) < console.canvasDrawImage("/interface/easel/delete.png:"..storage.buttonStates["frameDelete"], buttonPosition("frameDelete"), 1) < console.canvasDrawImage("/interface/easel/add.png:"..storage.buttonStates["frameAdd"], buttonPosition("frameAdd"), 1) < console.canvasDrawImage("/interface/easel/shiftleftright.png:right"..storage.buttonStates["shiftRight"], buttonPosition("shiftRight"), 1) < console.canvasDrawImage("/interface/easel/shiftleftright.png:left"..storage.buttonStates["shiftLeft"], buttonPosition("shiftLeft"), 1) < console.canvasDrawImage("/interface/easel/shiftupdown.png:up"..storage.buttonStates["shiftUp"], buttonPosition("shiftUp"), 1) < console.canvasDrawImage("/interface/easel/shiftupdown.png:down"..storage.buttonStates["shiftDown"], buttonPosition("shiftDown"), 1) < console.canvasDrawImage("/interface/easel/wiredicon.png:"..storage.buttonStates["isWired"], buttonPosition("isWired"), 1) < < if storage.lightData["f"..tostring(storage.currentFrame)] ~= nil then < local lightDirective = "?replace=828282="..(storage.lightData["f"..tostring(storage.currentFrame)] or "808080")..";FFFFFF=" ..(storage.lightData["f"..tostring(storage.currentFrame)] or "808080") < console.canvasDrawImage("/interface/easel/lightbutton.png:"..storage.buttonStates["lightSelect"]..lightDirective, buttonPosition("lightSelect"), 1) < else < console.canvasDrawImage("/interface/easel/lightbutton.png:"..storage.buttonStates["lightSelect"], buttonPosition("lightSelect"), 1) < end < local digit12 = storage.currentFrame % 10 < local digit11 = (storage.currentFrame - digit12)/10 < local digit22 = #storage.signPixels % 10 < local digit21 = (#storage.signPixels - digit22)/10 < console.canvasDrawImage("/interface/easel/numbers.png:"..digit11,buttonPosition("S:digit11"), 1) < console.canvasDrawImage("/interface/easel/numbers.png:"..digit12, buttonPosition("S:digit12"), 1) < console.canvasDrawImage("/interface/easel/numbers.png:"..digit21,buttonPosition("S:digit21"), 1) < console.canvasDrawImage("/interface/easel/numbers.png:"..digit22, buttonPosition("S:digit22"), 1) --(-1,3) < for x=1,32 do < for y=1,8 do < if storage.signPixels[storage.currentFrame][x][y] ~= 0 then < console.canvasDrawRect( < {buttonPosition("pixelPress")[1]-6+6*x, buttonPosition("pixelPress")[2]-6+6*y, buttonPosition("pixelPress")[1]+6*x, buttonPosition("pixelPress")[2]+6*y}, < convertRGBAtoArray(storage.signPixels[storage.currentFrame][x][y]) ) < end < end < end < ------------------- < --Template Anchor-- < ------------------- < console.canvasDrawImage("/interface/easel/statictemplates.png", buttonPosition("S:templates"), 1) --(-7,2) < console.canvasDrawImage("/interface/easel/clear.png:"..storage.buttonStates["clearPress"], buttonPosition("clearPress"), 1) --(4,8) < console.canvasDrawImage("/interface/easel/print.png:"..storage.buttonStates["printPress"], buttonPosition("printPress"), 1) --(8,8) < console.canvasDrawImage("/interface/easel/undo.png:"..storage.buttonStates["undoPress"], buttonPosition("undoPress"), 1) --(12,8) < console.canvasDrawImage("/interface/easel/manualinput.png:"..storage.buttonStates["nameInput"], buttonPosition("nameInput"), 1) --(-3,4) < console.canvasDrawText(storage.signName, {position=buttonPosition("S:signName")}, 10, {0,0,0,255}) < < if templates["fromContainer"] ~= nil then < console.canvasDrawImage("/interface/easel/"..templates["fromContainer"].currentIcon, vec2.add(buttonPosition("templateSlotCopy"), {3,4}), 1) end < if storage.buttonStates["templateSlotCopy"] == "highlight" then < console.canvasDrawRect(button4Position("templateSlotCopy"), {255,255,255,70}) end < < console.canvasDrawText(self.toolTip, {position=buttonPosition("S:toolTip")}, 8, {210,210,210,210}) < ---------------- < --Color Anchor-- < ---------------- < console.canvasDrawImage("/interface/easel/staticcolor.png", buttonPosition("S:colorStatics"), 1) --(12,8) < console.canvasDrawImage("/interface/easel/staticmodifiers.png", buttonPosition("S:modifierStatics"), 1) --(12,8) < console.canvasDrawImage("/interface/easel/pickericon.png:"..storage.buttonStates["pickToggle"], buttonPosition("pickToggle"), 1) --(19.5,3) < console.canvasDrawImage("/interface/easel/fillicon.png:"..storage.buttonStates["fillToggle"], buttonPosition("fillToggle"), 1) --(21,3) < console.canvasDrawRect(button4Position("S:colorDisplay"),convertRGBAtoArray(storage.paintColor)) < < < ---------------- < --Popup Anchors-- < ---------------- < if self.thrownError ~= nil then < console.canvasDrawImage("/interface/easel/errorpane.png", buttonPosition("S:errorWindow"), 1) < console.canvasDrawText(self.thrownError[2], {position=buttonPosition("S:errorPrompt1")},20,{220,0,0,255}) < console.canvasDrawText(self.thrownError[3], {position=buttonPosition("S:errorPrompt2")},20,{220,0,0,255}) < if self.thrownError[1] == 1 then self.thrownError = nil else self.thrownError[1] = self.thrownError[1] - 1 end < end < < if self.inputBoxMode ~= nil then < console.canvasDrawImage("/interface/easel/inputpane.png", buttonPosition("S:inputWindow"), 1) < console.canvasDrawText(self.inputBoxMode[1], {position=buttonPosition("S:inputPrompt")},15,{0,0,0,255}) < if self.blinking[1] then < console.canvasDrawText(self.inputBoxMode[2].."|", {position=buttonPosition("S:inputData")},15,{0,0,0,255}) < else < console.canvasDrawText(self.inputBoxMode[2], {position=buttonPosition("S:inputData")},15,{0,0,0,255}) < end < if self.blinking[2] == 0 then < self.blinking[1] = not self.blinking[1] < self.blinking[2] = 8 < else < self.blinking[2] = self.blinking[2] - 1 < end < end < < if self.colorSelectBox then < console.canvasDrawImage("/interface/easel/spectrumchart_window.png", buttonPosition("S:spectrumWindow"), 1) < console.canvasDrawImage("/interface/easel/spectrumchart_316_110.png", vec2.add(buttonPosition("spectrumPress"), {-3,-3}), 1) < end < < if self.showSpectrumCursor[1] > 0 then < console.canvasDrawImage("/interface/easel/spectrumcursor.png", vec2.add(self.showSpectrumCursor[2], {1,1}), 1) < self.showSpectrumCursor[1] = self.showSpectrumCursor[1]-1 < end --- > if storage.currentFrame > #storage.signPixels then storage.currentFrame = #storage.signPixels end > > --drawing all the bits, with relevant data dependencies > --------------- > --Main Anchor-- > --------------- > console.canvasDrawImage("/interface/easel/staticpanels.png", buttonPosition("S:mainStatics"), 1) > --console.canvasDrawImage("/interface/easel/icongrab.png:"..storage.buttonStates["iconGrab"],buttonPosition("iconGrab"), 1) > console.canvasDrawImage("/interface/easel/signbacking.png:"..storage.backingTypes[storage.backingTypesIndex], buttonPosition("pixelPress"), 1.5) > console.canvasDrawImage("/interface/easel/signframe.png:"..storage.frameTypes[storage.frameTypesIndex][1], buttonPosition("framePress"), 1.5) > console.canvasDrawImage("/interface/easel/minisignbacking.png:"..storage.backingTypes[storage.backingTypesIndex], buttonPosition("S:miniBacking"), 1) --(20,6.5) > console.canvasDrawImage("/interface/easel/scrollleft.png:"..storage.buttonStates["backingLeft"], buttonPosition("backingLeft"), 1) > console.canvasDrawImage("/interface/easel/scrollright.png:"..storage.buttonStates["backingRight"], buttonPosition("backingRight"), 1) > console.canvasDrawImage("/interface/easel/scrollleft.png:"..storage.buttonStates["frameLeft"], buttonPosition("frameLeft"), 1) > console.canvasDrawImage("/interface/easel/scrollright.png:"..storage.buttonStates["frameRight"], buttonPosition("frameRight"), 1) > console.canvasDrawImage("/interface/easel/delete.png:"..storage.buttonStates["frameDelete"], buttonPosition("frameDelete"), 1) > console.canvasDrawImage("/interface/easel/add.png:"..storage.buttonStates["frameAdd"], buttonPosition("frameAdd"), 1) > console.canvasDrawImage("/interface/easel/shiftleftright.png:right"..storage.buttonStates["shiftRight"], buttonPosition("shiftRight"), 1) > console.canvasDrawImage("/interface/easel/shiftleftright.png:left"..storage.buttonStates["shiftLeft"], buttonPosition("shiftLeft"), 1) > console.canvasDrawImage("/interface/easel/shiftupdown.png:up"..storage.buttonStates["shiftUp"], buttonPosition("shiftUp"), 1) > console.canvasDrawImage("/interface/easel/shiftupdown.png:down"..storage.buttonStates["shiftDown"], buttonPosition("shiftDown"), 1) > console.canvasDrawImage("/interface/easel/wiredicon.png:"..storage.buttonStates["isWired"], buttonPosition("isWired"), 1) > > if storage.lightData["f"..tostring(storage.currentFrame)] ~= nil then > local lightDirective = "?replace=828282="..(storage.lightData["f"..tostring(storage.currentFrame)] or "808080")..";FFFFFF=" ..(storage.lightData["f"..tostring(storage.currentFrame)] or "808080") > console.canvasDrawImage("/interface/easel/lightbutton.png:"..storage.buttonStates["lightSelect"]..lightDirective, buttonPosition("lightSelect"), 1) > else > console.canvasDrawImage("/interface/easel/lightbutton.png:"..storage.buttonStates["lightSelect"], buttonPosition("lightSelect"), 1) > end > local digit12 = storage.currentFrame % 10 > local digit11 = (storage.currentFrame - digit12)/10 > local digit22 = #storage.signPixels % 10 > local digit21 = (#storage.signPixels - digit22)/10 > console.canvasDrawImage("/interface/easel/numbers.png:"..digit11,buttonPosition("S:digit11"), 1) > console.canvasDrawImage("/interface/easel/numbers.png:"..digit12, buttonPosition("S:digit12"), 1) > console.canvasDrawImage("/interface/easel/numbers.png:"..digit21,buttonPosition("S:digit21"), 1) > console.canvasDrawImage("/interface/easel/numbers.png:"..digit22, buttonPosition("S:digit22"), 1) --(-1,3) > for x=1,32 do > for y=1,8 do > if storage.signPixels[storage.currentFrame][x][y] ~= 0 then > console.canvasDrawRect( > {buttonPosition("pixelPress")[1]-6+6*x, buttonPosition("pixelPress")[2]-6+6*y, buttonPosition("pixelPress")[1]+6*x, buttonPosition("pixelPress")[2]+6*y}, > convertRGBAtoArray(storage.signPixels[storage.currentFrame][x][y]) ) > end > end > end > ------------------- > --Template Anchor-- > ------------------- > console.canvasDrawImage("/interface/easel/clear.png:"..storage.buttonStates["clearPress"], buttonPosition("clearPress"), 1) --(4,8) > console.canvasDrawImage("/interface/easel/print.png:"..storage.buttonStates["printPress"], buttonPosition("printPress"), 1) --(8,8) > console.canvasDrawImage("/interface/easel/undo.png:"..storage.buttonStates["undoPress"], buttonPosition("undoPress"), 1) --(12,8) > > console.canvasDrawImage("/interface/easel/scaninput.png:"..storage.buttonStates["templateSlotScanButton"], buttonPosition("templateSlotScanButton"), 1) > console.canvasDrawImage("/interface/easel/iconthing.png", buttonPosition("templateSlotCopy"), 1) > if templates["fromContainer"] ~= nil then > console.canvasDrawImage("/interface/easel/"..templates["fromContainer"].currentIcon, vec2.add(buttonPosition("templateSlotCopy"), {1,0}), 1) > end > if storage.buttonStates["templateSlotCopy"] == "highlight" then > console.canvasDrawRect(button4Position("templateSlotCopy"), {255,255,255,70}) end > > ---------------- > --Color Anchor-- > ---------------- > console.canvasDrawImage("/interface/easel/staticcolor.png", buttonPosition("S:colorStatics"), 1) --(12,8) > console.canvasDrawImage("/interface/easel/pickericon.png:"..storage.buttonStates["pickToggle"], buttonPosition("pickToggle"), 1) --(19.5,3) > console.canvasDrawImage("/interface/easel/fillicon.png:"..storage.buttonStates["fillToggle"], buttonPosition("fillToggle"), 1) --(21,3) > console.canvasDrawRect(button4Position("S:colorDisplay"),convertRGBAtoArray(storage.paintColor)) > > > ---------------- > --Popup Anchors-- > ---------------- > if self.thrownError ~= nil then > console.canvasDrawImage("/interface/easel/errorpane.png", buttonPosition("S:errorWindow"), 1) > console.canvasDrawText(self.thrownError[2], {position=buttonPosition("S:errorPrompt1")},20,{220,0,0,255}) > console.canvasDrawText(self.thrownError[3], {position=buttonPosition("S:errorPrompt2")},20,{220,0,0,255}) > if self.thrownError[1] == 1 then self.thrownError = nil else self.thrownError[1] = self.thrownError[1] - 1 end > end > > if self.colorSelectBox then > console.canvasDrawImage("/interface/easel/spectrumchart_window.png", buttonPosition("S:spectrumWindow"), 1) > console.canvasDrawImage("/interface/easel/spectrumchart.png", buttonPosition("spectrumPress"), 1) > end > > if self.showSpectrumCursor[1] > 0 then > console.canvasDrawImage("/interface/easel/spectrumcursor.png", self.showSpectrumCursor[2], 1) > self.showSpectrumCursor[1] = self.showSpectrumCursor[1]-1 > end 484,513c406,435 < --the color selection box should override all. since one button works, the intercept goes here rather than in canvasClickEvent < if self.colorSelectBox then < pixelEntry = canvasButtonOffsets["spectrumPress"] < if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then < return "spectrumPress" < else < return nil < end < end < < --and since pixelPress overrides framePress, but pairs() process it later, it gets a special pass < local pixelEntry = canvasButtonOffsets["pixelPress"] < if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then < return "pixelPress" < end < < --and since pixelPress overrides framePress, but pairs() process it later, it gets a special pass < local pixelEntry = canvasButtonOffsets["shiftLeft"] < if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then < return "shiftLeft" < end < < for button, entry in pairs(canvasButtonOffsets) do < if string.sub(button, 1, 2) ~= "S:" and (canvasAnchors[entry[1]][1]+entry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[entry[1]][1]+entry[4]) and (canvasAnchors[entry[1]][2]+entry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[entry[1]][2]+entry[5]) then < if button ~= "spectrumPress" then < return button < end < end < end < return nil --- > --the color selection box should override all. since one button works, the intercept goes here rather than in canvasClickEvent > if self.colorSelectBox then > pixelEntry = canvasButtonOffsets["spectrumPress"] > if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then > return "spectrumPress" > else > return nil > end > end > > --and since pixelPress overrides framePress, but pairs() process it later, it gets a special pass > local pixelEntry = canvasButtonOffsets["pixelPress"] > if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then > return "pixelPress" > end > > --and since pixelPress overrides framePress, but pairs() process it later, it gets a special pass > local pixelEntry = canvasButtonOffsets["shiftLeft"] > if (canvasAnchors[pixelEntry[1]][1]+pixelEntry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[pixelEntry[1]][1]+pixelEntry[4]) and (canvasAnchors[pixelEntry[1]][2]+pixelEntry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[pixelEntry[1]][2]+pixelEntry[5]) then > return "shiftLeft" > end > > for button, entry in pairs(canvasButtonOffsets) do > if string.sub(button, 1, 2) ~= "S:" and (canvasAnchors[entry[1]][1]+entry[2] <= mousepos[1]) and (mousepos[1] <= canvasAnchors[entry[1]][1]+entry[4]) and (canvasAnchors[entry[1]][2]+entry[3] <= mousepos[2]) and (mousepos[2] <= canvasAnchors[entry[1]][2]+entry[5]) then > if button ~= "spectrumPress" then > return button > end > end > end > return nil 517,710c439,630 < --world.logInfo("Button: %s", button) < if button == "framePress" then --just cycles the frame index < pushToUndoStack({"framePress", storage.frameTypesIndex}) < if storage.frameTypesIndex < #storage.frameTypes then < storage.frameTypesIndex = storage.frameTypesIndex + 1 < else < storage.frameTypesIndex = 1 < end < elseif button == "backingRight" then --just shifts the backingindex < pushToUndoStack({"backingPress", storage.backingTypesIndex}) < if storage.backingTypesIndex < #storage.backingTypes then < storage.backingTypesIndex = storage.backingTypesIndex + 1 < else < storage.backingTypesIndex = 1 < end < elseif button == "backingLeft" then --just shifts the backing index < pushToUndoStack({"backingPress", storage.backingTypesIndex}) < if storage.backingTypesIndex == 1 then < storage.backingTypesIndex = #storage.backingTypes < else < storage.backingTypesIndex = storage.backingTypesIndex - 1 < end < elseif button == "frameRight" then --just chooses the current frame. I hate having two "frames" be relevant in this context. could have picked better terms at the start < if storage.currentFrame == #storage.signPixels then < storage.currentFrame = 1 < else < storage.currentFrame = storage.currentFrame + 1 < end < elseif button == "frameLeft" then --just chooses the current frame < if storage.currentFrame == 1 then < storage.currentFrame = #storage.signPixels < else < storage.currentFrame = storage.currentFrame - 1 < end < elseif button == "shiftRight" then --moves all the pixels on the frame at once < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) < storage.signPixels[storage.currentFrame] = pixelShift(1, 0) < elseif button == "shiftLeft" then --moves all the pixels on the frame at once < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) < storage.signPixels[storage.currentFrame] = pixelShift(-1, 0) < elseif button == "shiftUp" then --moves all the pixels on the frame at once < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) < storage.signPixels[storage.currentFrame] = pixelShift(0, 1) < elseif button == "shiftDown" then --moves all the pixels on the frame at once < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) < storage.signPixels[storage.currentFrame] = pixelShift(0, -1) < elseif button == "clearPress" then --removes all pixels from the current frame < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame],storage.lightData["f"..tostring(storage.currentFrame)]}) < for x=1,32 do < for y=1,8 do < storage.signPixels[storage.currentFrame][x][y] = 0 < end < end < storage.lightData["f"..tostring(storage.currentFrame)] = nil < elseif button == "isWired" then --toggles "wired" state < if storage.isWired then < storage.isWired = false < else < storage.isWired = true < end < elseif button == "frameAdd" then --copies the current frame to the end of the animation < pushToUndoStack({"removeFrame", #storage.signPixels + 1}) < storage.lightData["f"..tostring(#storage.signPixels + 1)] = storage.lightData["f"..tostring(storage.currentFrame)] < storage.signPixels[#storage.signPixels + 1] = tablecopy(storage.signPixels[storage.currentFrame]) < storage.currentFrame = #storage.signPixels < elseif button == "printPress" then --make me a sign! < outputSign() < elseif button == "frameDelete" then --removes current frame < pushToUndoStack({"insertFrame", storage.currentFrame, storage.signPixels[storage.currentFrame], storage.lightData["f"..tostring(storage.currentFrame)]}) < storage.lightData["f"..tostring(storage.currentFrame)] = nil < for i=1, #storage.signPixels do < if i >= storage.currentFrame then storage.lightData["f"..tostring(i)] = storage.lightData["f"..tostring(i+1)] end < end < table.remove(storage.signPixels, storage.currentFrame) < if storage.currentFrame ~= 1 then < storage.currentFrame = storage.currentFrame - 1 < end < elseif button == "iconGrab" then --totally deprecated, as this is automatic now. < pushToUndoStack({"restoreIcon", storage.currentIcon}) < local wireString = "" < local containerString = "" < if storage.buttonStates["isWired"] == "on" then wireString = "-wired" end < storage.currentIcon = "customicons.png:"..storage.backingTypes[storage.backingTypesIndex].."-"..storage.frameTypes[storage.frameTypesIndex][1]..wireString..containerString < elseif button == "undoPress" then --the undo button has to do, well, pretty much all that the other buttons do. just in reverse. < local action = self.undoStack[#self.undoStack] < --world.logInfo("Undoing %s", action) < if action[1] == "framePress" then < storage.frameTypesIndex = action[2] < elseif action[1] == "backingPress" then < storage.backingTypesIndex = action[2] < elseif action[1] == "restoreFrame" then < storage.signPixels[action[2]] = tablecopy(action[3]) < storage.lightData["f"..tostring(action[2])] = action[4] < elseif action[1] == "restoreSignPixels" then < storage.signPixels = tablecopy(action[2]) < storage.lightData = tablecopy(action[3]) < storage.currentFrame = #storage.signPixels < elseif action[1] == "removeFrame" then < if storage.currentFrame >= action[2] then storage.currentFrame = storage.currentFrame - 1 end < storage.lightData["f"..tostring(action[2])] = nil < for i=1, #storage.signPixels do < if i >= action[2] then storage.lightData["f"..tostring(i)] = storage.lightData["f"..tostring(i+1)] end < end < table.remove(storage.signPixels, storage.currentFrame) < table.remove(storage.signPixels,action[2]) < storage.lightData["f"..tostring(action[2])] = nil < elseif action[1] == "insertFrame" then < table.insert(storage.signPixels,action[2],tablecopy(action[3])) < storage.lightData["f"..tostring(action[2])] = action[4] < storage.currentFrame = action[2] < elseif action[1] == "restoreIcon" then < storage.currentIcon = action[2] < elseif action[1] == "reverseStroke" then < storage.currentFrame = action[2][3] < for i=2,#action do < setPixel(action[i][1], action[i][2], action[i][3]) < end < elseif action[1] == "restoreColor" then < storage.paintColor = action[2] < storage.paintAlpha = convertRGBAtoArray(action[2])[4] < self.showSpectrumCursor = {0, action[3]} < elseif action[1] == "restoreFromTemplate" then < storage.signPixels = action[2] < storage.frameTypesIndex = action[3] < storage.backingTypesIndex = action[4] < storage.isWired = action[5] < storage.currentIcon = action[7] < storage.signName = action[8] < storage.currentFrame = action[9] < storage.lightData = action[10] < elseif action[1] == "lightChange" then < storage.lightData["f"..tostring(action[2])] = action[3] < end < table.remove(self.undoStack) < elseif button == "spectrumPress" then --unlike painting, changing the color with the spectrum selector only "locks in" if mouseup is over it < pushToUndoStack({"restoreColor", storage.oldColor, position}) < storage.oldColor = nil < setSpectrum(position, 30) < elseif button == "pickToggle" then < if self.currentCursorModifier == "pickPixel" then self.currentCursorModifier = nil else self.currentCursorModifier = "pickPixel" end < elseif button == "fillToggle" then < if self.currentCursorModifier == "fillPixel" then self.currentCursorModifier = nil else self.currentCursorModifier = "fillPixel" end < elseif button == "pickPixel" then --since the paintbrush modifiers work by calling on virtual buttons, here that stuff executes < local selectPix = detectPixel(position) < local selectColor = storage.signPixels[storage.currentFrame][selectPix[1]][selectPix[2]] < if selectColor ~= 0 then < pushToUndoStack({"restoreColor", storage.paintColor, position}) < storage.paintColor = selectColor < self.currentCursorModifier = nil < end < elseif button == "fillPixel" then < pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) < recursiveFiller(detectPixel(position)) < elseif string.len(button) > 11 and string.sub(button, 1, 12) == "templateSlot" then --which template to load from? it's in the button name < local templateIndex = string.sub(button, 13) < if string.len(templateIndex) == 1 then < templateIndex = "slot"..templateIndex < else < templateIndex = "fromContainer" < end < pushToUndoStack({"restoreFromTemplate", storage.signPixels, storage.frameTypesIndex, storage.backingTypesIndex, storage.isWired, storage.currentIcon, storage.signName, storage.currentFrame, storage.lightData}) < if templates[templateIndex] ~= nil then --old signs might be missing some properties < storage.signPixels = tablecopy(templates[templateIndex].signPixels) < storage.frameTypesIndex = templates[templateIndex].frameTypesIndex or 1 < storage.backingTypesIndex = templates[templateIndex].backingTypesIndex or 1 < storage.isWired = templates[templateIndex].isWired or false < storage.currentIcon = templates[templateIndex].currentIcon or "customicons.png:blank-black" < storage.signName = templates[templateIndex].signName or "Sign" < storage.lightData = tablecopy(templates[templateIndex].lightData) or {} < if storage.currentFrame > #storage.signPixels then storage.currentFrame = #storage.signPixels end < end < elseif string.len(button) > 11 and string.sub(button, 1, 12) == "templateSave" then < local templateIndex = "slot"..tostring(string.sub(button, -1)) < templates[templateIndex] = {} < templates[templateIndex].signPixels = tablecopy(storage.signPixels) < templates[templateIndex].frameTypesIndex = storage.frameTypesIndex < templates[templateIndex].backingTypesIndex = storage.backingTypesIndex < templates[templateIndex].isWired = storage.isWired < templates[templateIndex].currentIcon = storage.currentIcon < templates[templateIndex].signName = storage.signName < templates[templateIndex].lightData = tablecopy(storage.lightData) < elseif button == "colorInput" then --these buttons enable window states - make no changes themseleves, but change how the interface takes input < --self.inputBoxMode = {"Input RGB (format: \"r.g.b\")","","color"} < self.colorSelectBox = true < elseif button == "nameInput" then < self.inputBoxMode = {"Input Name","","name"} < elseif button == "lightSelect" then < pushToUndoStack({"lightChange", storage.currentFrame, storage.lightData["f"..tostring(storage.currentFrame)]}) < if storage.lightData["f"..tostring(storage.currentFrame)] == string.sub(storage.paintColor, 1, -3) then < storage.lightData["f"..tostring(storage.currentFrame)] = nil < else < storage.lightData["f"..tostring(storage.currentFrame)] = string.sub(storage.paintColor, 1, -3) < end < end --- > --world.logInfo("Button: %s", button) > if button == "framePress" then --just cycles the frame index > pushToUndoStack({"framePress", storage.frameTypesIndex}) > if storage.frameTypesIndex < #storage.frameTypes then > storage.frameTypesIndex = storage.frameTypesIndex + 1 > else > storage.frameTypesIndex = 1 > end > elseif button == "backingRight" then --just shifts the backingindex > pushToUndoStack({"backingPress", storage.backingTypesIndex}) > if storage.backingTypesIndex < #storage.backingTypes then > storage.backingTypesIndex = storage.backingTypesIndex + 1 > else > storage.backingTypesIndex = 1 > end > elseif button == "backingLeft" then --just shifts the backing index > pushToUndoStack({"backingPress", storage.backingTypesIndex}) > if storage.backingTypesIndex == 1 then > storage.backingTypesIndex = #storage.backingTypes > else > storage.backingTypesIndex = storage.backingTypesIndex - 1 > end > elseif button == "frameRight" then --just chooses the current frame. I hate having two "frames" be relevant in this context. could have picked better terms at the start > if storage.currentFrame == #storage.signPixels then > storage.currentFrame = 1 > else > storage.currentFrame = storage.currentFrame + 1 > end > elseif button == "frameLeft" then --just chooses the current frame > if storage.currentFrame == 1 then > storage.currentFrame = #storage.signPixels > else > storage.currentFrame = storage.currentFrame - 1 > end > elseif button == "shiftRight" then --moves all the pixels on the frame at once > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) > storage.signPixels[storage.currentFrame] = pixelShift(1, 0) > elseif button == "shiftLeft" then --moves all the pixels on the frame at once > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) > storage.signPixels[storage.currentFrame] = pixelShift(-1, 0) > elseif button == "shiftUp" then --moves all the pixels on the frame at once > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) > storage.signPixels[storage.currentFrame] = pixelShift(0, 1) > elseif button == "shiftDown" then --moves all the pixels on the frame at once > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) > storage.signPixels[storage.currentFrame] = pixelShift(0, -1) > elseif button == "clearPress" then --removes all pixels from the current frame > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame],storage.lightData["f"..tostring(storage.currentFrame)]}) > for x=1,32 do > for y=1,8 do > storage.signPixels[storage.currentFrame][x][y] = 0 > end > end > storage.lightData["f"..tostring(storage.currentFrame)] = nil > elseif button == "isWired" then --toggles "wired" state > if storage.isWired then > storage.isWired = false > else > storage.isWired = true > end > elseif button == "frameAdd" then --copies the current frame to the end of the animation > pushToUndoStack({"removeFrame", #storage.signPixels + 1}) > storage.lightData["f"..tostring(#storage.signPixels + 1)] = storage.lightData["f"..tostring(storage.currentFrame)] > storage.signPixels[#storage.signPixels + 1] = tablecopy(storage.signPixels[storage.currentFrame]) > storage.currentFrame = #storage.signPixels > elseif button == "printPress" then --make me a sign! > outputSign() > elseif button == "frameDelete" then --removes current frame > pushToUndoStack({"insertFrame", storage.currentFrame, storage.signPixels[storage.currentFrame], storage.lightData["f"..tostring(storage.currentFrame)]}) > storage.lightData["f"..tostring(storage.currentFrame)] = nil > for i=1, #storage.signPixels do > if i >= storage.currentFrame then storage.lightData["f"..tostring(i)] = storage.lightData["f"..tostring(i+1)] end > end > table.remove(storage.signPixels, storage.currentFrame) > if storage.currentFrame ~= 1 then > storage.currentFrame = storage.currentFrame - 1 > end > elseif button == "iconGrab" then --totally deprecated, as this is automatic now. > pushToUndoStack({"restoreIcon", storage.currentIcon}) > local wireString = "" > local containerString = "" > if storage.buttonStates["isWired"] == "on" then wireString = "-wired" end > storage.currentIcon = "customicons.png:"..storage.backingTypes[storage.backingTypesIndex].."-"..storage.frameTypes[storage.frameTypesIndex][1]..wireString..containerString > elseif button == "undoPress" and #self.undoStack > 0 then --the undo button has to do, well, pretty much all that the other buttons do. just in reverse. > local action = self.undoStack[#self.undoStack] > --world.logInfo("Undoing %s", action) > if action[1] == "framePress" then > storage.frameTypesIndex = action[2] > elseif action[1] == "backingPress" then > storage.backingTypesIndex = action[2] > elseif action[1] == "restoreFrame" then > storage.signPixels[action[2]] = tablecopy(action[3]) > storage.lightData["f"..tostring(action[2])] = action[4] > elseif action[1] == "restoreSignPixels" then > storage.signPixels = tablecopy(action[2]) > storage.lightData = tablecopy(action[3]) > storage.currentFrame = #storage.signPixels > elseif action[1] == "removeFrame" then > if storage.currentFrame >= action[2] then storage.currentFrame = storage.currentFrame - 1 end > storage.lightData["f"..tostring(action[2])] = nil > for i=1, #storage.signPixels do > if i >= action[2] then storage.lightData["f"..tostring(i)] = storage.lightData["f"..tostring(i+1)] end > end > table.remove(storage.signPixels, storage.currentFrame) > table.remove(storage.signPixels,action[2]) > storage.lightData["f"..tostring(action[2])] = nil > elseif action[1] == "insertFrame" then > table.insert(storage.signPixels,action[2],tablecopy(action[3])) > storage.lightData["f"..tostring(action[2])] = action[4] > storage.currentFrame = action[2] > elseif action[1] == "restoreIcon" then > storage.currentIcon = action[2] > elseif action[1] == "reverseStroke" then > storage.currentFrame = action[2][3] > for i=2,#action do > setPixel(action[i][1], action[i][2], action[i][3]) > end > elseif action[1] == "restoreColor" then > storage.paintColor = action[2] > storage.paintAlpha = convertRGBAtoArray(action[2])[4] > self.showSpectrumCursor = {0, action[3]} > elseif action[1] == "restoreFromTemplate" then > storage.signPixels = action[2] > storage.frameTypesIndex = action[3] > storage.backingTypesIndex = action[4] > storage.isWired = action[5] > storage.currentIcon = action[6] > storage.signName = action[7] > storage.currentFrame = action[8] > storage.lightData = action[9] > elseif action[1] == "lightChange" then > storage.lightData["f"..tostring(action[2])] = action[3] > end > table.remove(self.undoStack) > elseif button == "spectrumPress" then --unlike painting, changing the color with the spectrum selector only "locks in" if mouseup is over it > pushToUndoStack({"restoreColor", storage.oldColor, position}) > storage.oldColor = nil > setSpectrum(position, 30) > elseif button == "pickToggle" then > if self.currentCursorModifier == "pickPixel" then self.currentCursorModifier = nil else self.currentCursorModifier = "pickPixel" end > elseif button == "fillToggle" then > if self.currentCursorModifier == "fillPixel" then self.currentCursorModifier = nil else self.currentCursorModifier = "fillPixel" end > elseif button == "pickPixel" then --since the paintbrush modifiers work by calling on virtual buttons, here that stuff executes > local selectPix = detectPixel(position) > local selectColor = storage.signPixels[storage.currentFrame][selectPix[1]][selectPix[2]] > if selectColor ~= 0 then > pushToUndoStack({"restoreColor", storage.paintColor, position}) > storage.paintColor = selectColor > self.currentCursorModifier = nil > end > elseif button == "fillPixel" then > pushToUndoStack({"restoreFrame", storage.currentFrame, storage.signPixels[storage.currentFrame]}) > recursiveFiller(detectPixel(position)) > elseif string.len(button) > 11 and string.sub(button, 1, 12) == "templateSlot" then --which template to load from? it's in the button name > local templateIndex = string.sub(button, 13) > if string.len(templateIndex) == 1 then > templateIndex = "slot"..templateIndex > else > templateIndex = "fromContainer" > end > pushToUndoStack({"restoreFromTemplate", storage.signPixels, storage.frameTypesIndex, storage.backingTypesIndex, storage.isWired, storage.currentIcon, storage.signName, storage.currentFrame, storage.lightData}) > if templates[templateIndex] ~= nil then --old signs might be missing some properties > storage.signPixels = tablecopy(templates[templateIndex].signPixels) > storage.frameTypesIndex = templates[templateIndex].frameTypesIndex or 1 > storage.backingTypesIndex = templates[templateIndex].backingTypesIndex or 1 > storage.isWired = templates[templateIndex].isWired or false > storage.currentIcon = templates[templateIndex].currentIcon or "customicons.png:blank-black" > storage.signName = templates[templateIndex].signName or "Sign" > storage.lightData = tablecopy(templates[templateIndex].lightData) or {} > if storage.currentFrame > #storage.signPixels then storage.currentFrame = #storage.signPixels end > end > elseif string.len(button) > 11 and string.sub(button, 1, 12) == "templateSave" then > local templateIndex = "slot"..tostring(string.sub(button, -1)) > templates[templateIndex] = {} > templates[templateIndex].signPixels = tablecopy(storage.signPixels) > templates[templateIndex].frameTypesIndex = storage.frameTypesIndex > templates[templateIndex].backingTypesIndex = storage.backingTypesIndex > templates[templateIndex].isWired = storage.isWired > templates[templateIndex].currentIcon = storage.currentIcon > templates[templateIndex].signName = storage.signName > templates[templateIndex].lightData = tablecopy(storage.lightData) > elseif button == "colorInput" then --these buttons enable window states - make no changes themseleves, but change how the interface takes input > --self.inputBoxMode = {"Input RGB (format: \"r.g.b\")","","color"} > self.colorSelectBox = true > elseif button == "lightSelect" then > pushToUndoStack({"lightChange", storage.currentFrame, storage.lightData["f"..tostring(storage.currentFrame)]}) > if storage.lightData["f"..tostring(storage.currentFrame)] == string.sub(storage.paintColor, 1, -3) then > storage.lightData["f"..tostring(storage.currentFrame)] = nil > else > storage.lightData["f"..tostring(storage.currentFrame)] = string.sub(storage.paintColor, 1, -3) > end > end 714,726c634,646 < --for finding where you are on the main body of the sign < local returnPixel = nil < local pixBounds = {canvasAnchors[canvasButtonOffsets["pixelPress"][1]][1]+canvasButtonOffsets["pixelPress"][2], < canvasAnchors[canvasButtonOffsets["pixelPress"][1]][2]+canvasButtonOffsets["pixelPress"][3], < canvasAnchors[canvasButtonOffsets["pixelPress"][1]][1]+canvasButtonOffsets["pixelPress"][4], < canvasAnchors[canvasButtonOffsets["pixelPress"][1]][2]+canvasButtonOffsets["pixelPress"][5] < } < if (pixBounds[1] <= mousepos[1]) and (mousepos[1] <= pixBounds[3]) and (pixBounds[2] <= mousepos[2]) and (mousepos[2] <= pixBounds[4]) then < returnPixel = {} < returnPixel[1] = math.floor(1+(mousepos[1]-pixBounds[1])/6) < returnPixel[2] = math.floor(1+(mousepos[2]-pixBounds[2])/6) < end < return returnPixel --- > --for finding where you are on the main body of the sign > local returnPixel = nil > local pixBounds = {canvasAnchors[canvasButtonOffsets["pixelPress"][1]][1]+canvasButtonOffsets["pixelPress"][2], > canvasAnchors[canvasButtonOffsets["pixelPress"][1]][2]+canvasButtonOffsets["pixelPress"][3], > canvasAnchors[canvasButtonOffsets["pixelPress"][1]][1]+canvasButtonOffsets["pixelPress"][4], > canvasAnchors[canvasButtonOffsets["pixelPress"][1]][2]+canvasButtonOffsets["pixelPress"][5] > } > if (pixBounds[1] <= mousepos[1]) and (mousepos[1] <= pixBounds[3]) and (pixBounds[2] <= mousepos[2]) and (mousepos[2] <= pixBounds[4]) then > returnPixel = {} > returnPixel[1] = math.floor(1+(mousepos[1]-pixBounds[1])/6) > returnPixel[2] = math.floor(1+(mousepos[2]-pixBounds[2])/6) > end > return returnPixel 730,741c650,661 < --this function used to have to do more, so it looks messy for what little it does < if (0 < pixel[1]) and (pixel[1] < 33) and (0 < pixel[2]) and (pixel[2] < 9) then < if type(forceFrame) ~= "number" then < if value ~= storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]] then < --undo substack to keep track of a full stroke < table.insert(self.undoSubStack, {pixel, storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]], storage.currentFrame}) < storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]] = value < end < else < storage.signPixels[forceFrame][pixel[1]][pixel[2]] = value < end < end --- > --this function used to have to do more, so it looks messy for what little it does > if (0 < pixel[1]) and (pixel[1] < 33) and (0 < pixel[2]) and (pixel[2] < 9) then > if type(forceFrame) ~= "number" then > if value ~= storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]] then > --undo substack to keep track of a full stroke > table.insert(self.undoSubStack, {pixel, storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]], storage.currentFrame}) > storage.signPixels[storage.currentFrame][pixel[1]][pixel[2]] = value > end > else > storage.signPixels[forceFrame][pixel[1]][pixel[2]] = value > end > end 745,749c665,669 < table.insert(self.undoStack, tablecopy(newAction)) < storage.buttonStates["undoPress"] = "normal" < if #self.undoStack > 50 then < table.remove(self.undoStack, 1) < end --- > table.insert(self.undoStack, tablecopy(newAction)) > storage.buttonStates["undoPress"] = "normal" > if #self.undoStack > 50 then > table.remove(self.undoStack, 1) > end 753,771c673,691 < --returns a shifted version of the current frame < --would like to have the bleed stored somehow, but seemed hard to do nicely < local tempFrame = {} < for x=1,32 do < tempFrame[x] = {} < for y=1,8 do < tempFrame[x][y] = 0 < end < end < for x=1,32 do < for y=1,8 do < if (x==1 and h == 1) or (x==32 and h==-1) or (y==1 and v==1) or (y==8 and v==-1) then < tempFrame[x][y] = 0 < else < tempFrame[x][y] = storage.signPixels[storage.currentFrame][x - h][y - v] < end < end < end < return tempFrame --- > --returns a shifted version of the current frame > --would like to have the bleed stored somehow, but seemed hard to do nicely > local tempFrame = {} > for x=1,32 do > tempFrame[x] = {} > for y=1,8 do > tempFrame[x][y] = 0 > end > end > for x=1,32 do > for y=1,8 do > if (x==1 and h == 1) or (x==32 and h==-1) or (y==1 and v==1) or (y==8 and v==-1) then > tempFrame[x][y] = 0 > else > tempFrame[x][y] = storage.signPixels[storage.currentFrame][x - h][y - v] > end > end > end > return tempFrame 775,806c695,726 < --the relevant string parsing for inputs < local isInvalid = false < if stringType == "name" then < if input ~= "" then storage.signName = input end < elseif stringType == "alpha" then < if tonumber(input) ~= nil and 0 <= tonumber(input) and tonumber(input) < 256 then < pushToUndoStack({"restoreColor", storage.paintColor}) < storage.paintAlpha = tonumber(input) < local rgba = convertRGBAtoArray(storage.paintColor) < storage.paintColor = convertArraytoRGBA({rgba[1], rgba[2], rgba[3]}) < else < isInvalid = true < end < --the color input is defunct now I suppose < elseif stringType == "color" then < --mmm patterns I should use more of those < if input == string.match(input, "%d+[.]%d+[.]%d+") then < local r, g, b = string.match(input, "(%d+)[.](%d+)[.](%d+)") < r = tonumber(r) g = tonumber(g) b = tonumber(b) < if 0 <= r and r < 256 and 0 <= g and g < 256 and 0 <= b and b < 256 then < pushToUndoStack({"restoreColor", storage.paintColor}) < storage.paintColor = convertArraytoRGBA({r,g,b}) < else < isInvalid = true < end < else < isInvalid = true < end < end < if isInvalid then < self.thrownError = {300, "ERROR! INVALID ARGUMENT", "OBEY GIVEN CRITERIA"} < end --- > --the relevant string parsing for inputs > local isInvalid = false > if stringType == "name" then > if input ~= "" then storage.signName = input end > elseif stringType == "alpha" then > if tonumber(input) ~= nil and 0 <= tonumber(input) and tonumber(input) < 256 then > pushToUndoStack({"restoreColor", storage.paintColor}) > storage.paintAlpha = tonumber(input) > local rgba = convertRGBAtoArray(storage.paintColor) > storage.paintColor = convertArraytoRGBA({rgba[1], rgba[2], rgba[3]}) > else > isInvalid = true > end > --the color input is defunct now I suppose > elseif stringType == "color" then > --mmm patterns I should use more of those > if input == string.match(input, "%d+[.]%d+[.]%d+") then > local r, g, b = string.match(input, "(%d+)[.](%d+)[.](%d+)") > r = tonumber(r) g = tonumber(g) b = tonumber(b) > if 0 <= r and r < 256 and 0 <= g and g < 256 and 0 <= b and b < 256 then > pushToUndoStack({"restoreColor", storage.paintColor}) > storage.paintColor = convertArraytoRGBA({r,g,b}) > else > isInvalid = true > end > else > isInvalid = true > end > end > if isInvalid then > self.thrownError = {300, "ERROR! INVALID ARGUMENT", "OBEY GIVEN CRITERIA"} > end 814,821c734,741 < --Usually the script will grab an item drop before a player can, but hedgeing bets < dropSpot = world.entityPosition(console.sourceEntity()) < dropSpot = {dropSpot[1] - 4, dropSpot[2] + 4} < local findPlayerlessSpot = world.playerQuery(dropSpot,4) < if findPlayerlessSpot ~= nil then dropSpot = {dropSpot[1]+12,dropSpot[2]} end < world.callScriptedEntity(console.sourceEntity(), "requestSignDrop", dropSpot) < --world.logInfo("Requesting drop from %s at %s", console.sourceEntity(), dropSpot) < self.lookingForSignDrop = 25 --- > --Usually the script will grab an item drop before a player can, but hedgeing bets > dropSpot = world.entityPosition(console.sourceEntity()) > dropSpot = {dropSpot[1] - 4, dropSpot[2] + 4} > local findPlayerlessSpot = world.playerQuery(dropSpot,4) > if findPlayerlessSpot ~= nil then dropSpot = {dropSpot[1]+12,dropSpot[2]} end > world.callScriptedEntity(console.sourceEntity(), "requestSignDrop", dropSpot) > --world.logInfo("Requesting drop from %s at %s", console.sourceEntity(), dropSpot) > self.lookingForSignDrop = 25 825,864c745,784 < --scans around the drop point for a sign drop < local foundDroppedSign = false < self.droppedSign = world.itemDropQuery(args, 5) < for p,q in ipairs(self.droppedSign) do < if world.entityName(q) == "Body-customsign" or world.entityName(q) == "Body-customsigncontainer" then < self.droppedSign = q < foundDroppedSign = true < break < end < end < if foundDroppedSign == true then < --world.logInfo("Sign drop found") < self.lookingForSignDrop = 0 < self.droppedSign = world.takeItemDrop(self.droppedSign, console.sourceEntity()) < if self.droppedSign ~= nil then < templates["fromContainer"] = {} < --world.logInfo("Dropped sign: %s", data.droppedSign) < templates["fromContainer"].signPixels = deconstructDirectiveStrings(self.droppedSign["parameters"]["signData"], self.droppedSign["parameters"]["lightData"]) < templates["fromContainer"].frameTypesIndex = self.droppedSign["parameters"]["frameColors"] < for p,q in ipairs(storage.frameTypes) do < if templates["fromContainer"].frameTypesIndex[1] == q[2] and templates["fromContainer"].frameTypesIndex[2] == q[3] then < templates["fromContainer"].frameTypesIndex = p break < end < end < templates["fromContainer"].backingTypesIndex = self.droppedSign["parameters"]["signBacking"] < for p,q in ipairs(storage.backingTypes) do < if templates["fromContainer"].backingTypesIndex == q then templates["fromContainer"].backingTypesIndex = p break end < end < if self.droppedSign["parameters"]["isWired"] then < templates["fromContainer"].isWired = true < else < templates["fromContainer"].isWired = false < end < templates["fromContainer"].currentIcon = self.droppedSign["parameters"]["inventoryIcon"] < templates["fromContainer"].signName = self.droppedSign["parameters"]["signName"] < templates["fromContainer"].lightData = self.droppedSign["parameters"]["lightData"] or {} < end < else < self.lookingForSignDrop = self.lookingForSignDrop - 1 < end --- > --scans around the drop point for a sign drop > local foundDroppedSign = false > self.droppedSign = world.itemDropQuery(args, 5) > for p,q in ipairs(self.droppedSign) do > if world.entityName(q) == "customsign" or world.entityName(q) == "customsigncontainer" then > self.droppedSign = q > foundDroppedSign = true > break > end > end > if foundDroppedSign == true then > --world.logInfo("Sign drop found") > self.lookingForSignDrop = 0 > self.droppedSign = world.takeItemDrop(self.droppedSign, console.sourceEntity()) > if self.droppedSign ~= nil then > templates["fromContainer"] = {} > --world.logInfo("Dropped sign: %s", data.droppedSign) > templates["fromContainer"].signPixels = deconstructDirectiveStrings(self.droppedSign["parameters"]["signData"], self.droppedSign["parameters"]["lightData"]) > templates["fromContainer"].frameTypesIndex = self.droppedSign["parameters"]["frameColors"] > for p,q in ipairs(storage.frameTypes) do > if templates["fromContainer"].frameTypesIndex[1] == q[2] and templates["fromContainer"].frameTypesIndex[2] == q[3] then > templates["fromContainer"].frameTypesIndex = p break > end > end > templates["fromContainer"].backingTypesIndex = self.droppedSign["parameters"]["signBacking"] > for p,q in ipairs(storage.backingTypes) do > if templates["fromContainer"].backingTypesIndex == q then templates["fromContainer"].backingTypesIndex = p break end > end > if self.droppedSign["parameters"]["isWired"] then > templates["fromContainer"].isWired = true > else > templates["fromContainer"].isWired = false > end > templates["fromContainer"].currentIcon = self.droppedSign["parameters"]["inventoryIcon"] > templates["fromContainer"].signName = self.droppedSign["parameters"]["signName"] > templates["fromContainer"].lightData = self.droppedSign["parameters"]["lightData"] or {} > end > else > self.lookingForSignDrop = self.lookingForSignDrop - 1 > end 868,891c788,811 < --strings have format: replace=rrggbbaa=rrggbbaa;rrggbbaa=rrggbbaa;etc. < local temporaryPixels = {{}} < local pix = 1 local piy = 1 < for i=1,#directiveStrings do < temporaryPixels[i] = {} < for x=1,32 do < temporaryPixels[i][x] = {} < for y=1,8 do < temporaryPixels[i][x][y] = 0 < end < end < if directiveStrings[i] ~= nil then < --I should use string.match here, but I wrote it before I found that function and it works so... < p = 9 < while (p + 16 <= #directiveStrings[i]) do < pix = tonumber(string.sub(directiveStrings[i], p, p+1)) < piy = tonumber(string.sub(directiveStrings[i], p+4, p+5)) < --world.logInfo("Frame %s, Pixel %s,%s", i, pix, piy) < temporaryPixels[i][pix][piy] = string.sub(directiveStrings[i], p+9, p+16) < p = p + 18 < end < end < end < return temporaryPixels --- > --strings have format: replace=rrggbbaa=rrggbbaa;rrggbbaa=rrggbbaa;etc. > local temporaryPixels = {{}} > local pix = 1 local piy = 1 > for i=1,#directiveStrings do > temporaryPixels[i] = {} > for x=1,32 do > temporaryPixels[i][x] = {} > for y=1,8 do > temporaryPixels[i][x][y] = 0 > end > end > if directiveStrings[i] ~= nil then > --I should use string.match here, but I wrote it before I found that function and it works so... > p = 9 > while (p + 16 <= #directiveStrings[i]) do > pix = tonumber(string.sub(directiveStrings[i], p, p+1)) > piy = tonumber(string.sub(directiveStrings[i], p+4, p+5)) > --world.logInfo("Frame %s, Pixel %s,%s", i, pix, piy) > temporaryPixels[i][pix][piy] = string.sub(directiveStrings[i], p+9, p+16) > p = p + 18 > end > end > end > return temporaryPixels 895c815 < --world.logInfo("//////////Printing Sign//////////") --- > --world.logInfo("//////////Printing Sign//////////") 897,943c817,862 < if storage.isWired then < inNodesToAdd = {{0,0}} < outNodesToAdd = {{3,0}} < else < inNodesToAdd = nil < outNodesToAdd = nil < end < convertToDirectiveString() < < local parameters = {} < local itemName = "" < itemName = "Body-customsign" < parameters.signData = storage.signDirectiveStrings < parameters.inventoryIcon = storage.currentIcon < parameters.signBacking = storage.backingTypes[storage.backingTypesIndex] < parameters.frameColors = {storage.frameTypes[storage.frameTypesIndex][2], storage.frameTypes[storage.frameTypesIndex][3]} < parameters.inboundNodes = inNodesToAdd < parameters.outboundNodes = outNodesToAdd < parameters.isWired = storage.isWired < parameters.lightData = storage.lightData < world.logInfo("%s", parameters.lightData) < parameters.animationParts = {["background"] = storage.backingTypes[storage.backingTypesIndex]} < parameters.signName = storage.signName < --world.logInfo("Wired: %s - Container: %s - Backing: %s - Frame: %s", storage.isWired, storage.isContainer, storage.backingTypes[storage.backingTypesIndex], storage.frameTypes[storage.frameTypesIndex][2]) < --world.logInfo("%s", storage.signDirectiveStrings") < local signToPlace = {} < local signInSlot = nil < local placementSlot = false < signToPlace.name = itemName < signToPlace.count = 1 < signToPlace.parameters = parameters < --world.logInfo("Sign To Place: %s", signToPlace) < --I don't want to use a less specific fucntion to add the signs to the container because no output should go in the input slot < for i=0,7 do < signInSlot = world.containerItemAt(self.matchingCabinet,i) < --world.logInfo("%s", signInSlot) < if signInSlot == nil or table.tostring(signInSlot.parameters) == table.tostring(parameters) then < placementSlot = i < break < end < end < if type(placementSlot) == "number" then < world.callScriptedEntity(console.sourceEntity(), "putInChest", signToPlace, placementSlot) < else < self.thrownError = {500, " ERROR! NANO-PAPER JAM", " PLEASE CLEAR OUTPUT"} < end < --world.logInfo("---------------------------------") --- > if storage.isWired then > inNodesToAdd = {{0,0}} > outNodesToAdd = {{3,0}} > else > inNodesToAdd = nil > outNodesToAdd = nil > end > convertToDirectiveString() > > local parameters = {} > local itemName = "" > itemName = "customsign" > parameters.signData = storage.signDirectiveStrings > parameters.inventoryIcon = storage.currentIcon > parameters.signBacking = storage.backingTypes[storage.backingTypesIndex] > parameters.frameColors = {storage.frameTypes[storage.frameTypesIndex][2], storage.frameTypes[storage.frameTypesIndex][3]} > parameters.inboundNodes = inNodesToAdd > parameters.outboundNodes = outNodesToAdd > parameters.isWired = storage.isWired > parameters.lightData = storage.lightData > parameters.animationParts = {["background"] = storage.backingTypes[storage.backingTypesIndex]} > parameters.signName = storage.signName > --world.logInfo("Wired: %s - Container: %s - Backing: %s - Frame: %s", storage.isWired, storage.isContainer, storage.backingTypes[storage.backingTypesIndex], storage.frameTypes[storage.frameTypesIndex][2]) > --world.logInfo("%s", storage.signDirectiveStrings") > local signToPlace = {} > local signInSlot = nil > local placementSlot = false > signToPlace.name = itemName > signToPlace.count = 1 > signToPlace.parameters = parameters > --world.logInfo("Sign To Place: %s", signToPlace) > --I don't want to use a less specific fucntion to add the signs to the container because no output should go in the input slot > for i=0,7 do > signInSlot = world.containerItemAt(self.matchingCabinet,i) > --world.logInfo("%s", signInSlot) > if signInSlot == nil or table.tostring(signInSlot.parameters) == table.tostring(parameters) then > placementSlot = i > break > end > end > if type(placementSlot) == "number" then > world.callScriptedEntity(console.sourceEntity(), "putInChest", signToPlace, placementSlot) > else > self.thrownError = {500, " ERROR! NANO-PAPER JAM", " PLEASE CLEAR OUTPUT"} > end > --world.logInfo("---------------------------------") 947,972c866,891 < storage.signDirectiveStrings = {} < local subDirective = "replace=" < local oldDirective = "" < local needSemicolon = false < for i=1,#storage.signPixels do < subDirective = "replace=" < needSemicolon = false < --in the sign, x and y are indexed with r and b, respectively < for x=1,32 do < for y=1,8 do < if storage.signPixels[i][x][y] ~= 0 then < if needSemicolon then subDirective = subDirective..";" else needSemicolon = true end < if x<10 then < subDirective = subDirective .. "0" .. x .. "000" .. y .. "01=" .. storage.signPixels[i][x][y] < else < subDirective = subDirective .. x .. "000" .. y .. "01=" .. storage.signPixels[i][x][y] < end < end < end < end < --if a frame doesn't change from the last, might as use those savings - that entry will be nil < if subDirective ~= oldDirective then < storage.signDirectiveStrings[i] = subDirective < oldDirective = subDirective < end < end --- > storage.signDirectiveStrings = {} > local subDirective = "replace=" > local oldDirective = "" > local needSemicolon = false > for i=1,#storage.signPixels do > subDirective = "replace=" > needSemicolon = false > --in the sign, x and y are indexed with r and b, respectively > for x=1,32 do > for y=1,8 do > if storage.signPixels[i][x][y] ~= 0 then > if needSemicolon then subDirective = subDirective..";" else needSemicolon = true end > if x<10 then > subDirective = subDirective .. "0" .. x .. "000" .. y .. "01=" .. storage.signPixels[i][x][y] > else > subDirective = subDirective .. x .. "000" .. y .. "01=" .. storage.signPixels[i][x][y] > end > end > end > end > --if a frame doesn't change from the last, might as use those savings - that entry will be nil > if subDirective ~= oldDirective then > storage.signDirectiveStrings[i] = subDirective > oldDirective = subDirective > end > end 979,980c898,899 < if canvasButtonOffsets[button] == nil then world.logInfo("%s", button) end < return {canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][2], canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][3]} --- > if canvasButtonOffsets[button] == nil then world.logInfo("%s", button) end > return {canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][2], canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][3]} 984,985c903,904 < return {canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][2], canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][3], < canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][4]+1, canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][5]+1} --- > return {canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][2], canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][3], > canvasAnchors[canvasButtonOffsets[button][1]][1]+canvasButtonOffsets[button][4]+1, canvasAnchors[canvasButtonOffsets[button][1]][2]+canvasButtonOffsets[button][5]+1} 989,1000c908,919 < --stupid lua and its stupid table pointers < --i keep forgetting it works that way, no end of grief < if input == nil then return nil end < if type(input) ~= "table" then < local newinput = input < return newinput < end < local newtab = {} < for i,j in pairs(input) do < newtab[i] = tablecopy(j) < end < return newtab --- > --stupid lua and its stupid table pointers > --i keep forgetting it works that way, no end of grief > if input == nil then return nil end > if type(input) ~= "table" then > local newinput = input > return newinput > end > local newtab = {} > for i,j in pairs(input) do > newtab[i] = tablecopy(j) > end > return newtab 1005,1016c924,935 < --not the most sophisticated of fill tools, but it does a decent job < --world.logInfo("Filling at position %s: %s to %s", p, storage.paintColor, oc) < if 1<=p[1] and p[1]<=32 and 1<=p[2] and p[2]<=8 then < local testColor = storage.signPixels[storage.currentFrame][p[1]][p[2]] < if testColor ~= storage.paintColor and (oc == nil or testColor == oc) then < storage.signPixels[storage.currentFrame][p[1]][p[2]] = storage.paintColor < recursiveFiller({p[1]-1,p[2]}, testColor) < recursiveFiller({p[1]+1,p[2]}, testColor) < recursiveFiller({p[1],p[2]-1}, testColor) < recursiveFiller({p[1],p[2]+1}, testColor) < end < end --- > --not the most sophisticated of fill tools, but it does a decent job > --world.logInfo("Filling at position %s: %s to %s", p, storage.paintColor, oc) > if 1<=p[1] and p[1]<=32 and 1<=p[2] and p[2]<=8 then > local testColor = storage.signPixels[storage.currentFrame][p[1]][p[2]] > if testColor ~= storage.paintColor and (oc == nil or testColor == oc) then > storage.signPixels[storage.currentFrame][p[1]][p[2]] = storage.paintColor > recursiveFiller({p[1]-1,p[2]}, testColor) > recursiveFiller({p[1]+1,p[2]}, testColor) > recursiveFiller({p[1],p[2]-1}, testColor) > recursiveFiller({p[1],p[2]+1}, testColor) > end > end 1020,1061c939,980 < --except when theyre highlighted, the state dependence of all buttons is handled here < if #storage.signPixels == 1 then < storage.buttonStates["frameDelete"] = "grayed" < else < storage.buttonStates["frameDelete"] = "normal" < end < < if #storage.signPixels >= 99 then < storage.buttonStates["frameAdd"] = "grayed" < else < storage.buttonStates["frameAdd"] = "normal" < end < < if storage.isWired then < storage.buttonStates["isWired"] = "on" < else < storage.buttonStates["isWired"] = "off" < end < < if self.currentCursorModifier == "pickPixel" then < storage.buttonStates["pickToggle"] = "on" < else < storage.buttonStates["pickToggle"] = "off" < end < < if self.currentCursorModifier == "fillPixel" then < storage.buttonStates["fillToggle"] = "on" < else < storage.buttonStates["fillToggle"] = "off" < end < < if self.undoStack == {} or self.undoStack[#self.undoStack] == nil then < storage.buttonStates["undoPress"] = "grayed" < else < storage.buttonStates["undoPress"] = "normal" < end < < if storage.lightData["f"..tostring(storage.currentFrame)] ~= nil then < storage.buttonStates["lightSelect"] = "on" < else < storage.buttonStates["lightSelect"] = "off" < end --- > --except when theyre highlighted, the state dependence of all buttons is handled here > if #storage.signPixels == 1 then > storage.buttonStates["frameDelete"] = "grayed" > else > storage.buttonStates["frameDelete"] = "normal" > end > > if #storage.signPixels >= 99 then > storage.buttonStates["frameAdd"] = "grayed" > else > storage.buttonStates["frameAdd"] = "normal" > end > > if storage.isWired then > storage.buttonStates["isWired"] = "on" > else > storage.buttonStates["isWired"] = "off" > end > > if self.currentCursorModifier == "pickPixel" then > storage.buttonStates["pickToggle"] = "on" > else > storage.buttonStates["pickToggle"] = "off" > end > > if self.currentCursorModifier == "fillPixel" then > storage.buttonStates["fillToggle"] = "on" > else > storage.buttonStates["fillToggle"] = "off" > end > > if self.undoStack == {} or self.undoStack[#self.undoStack] == nil then > storage.buttonStates["undoPress"] = "grayed" > else > storage.buttonStates["undoPress"] = "normal" > end > > if storage.lightData["f"..tostring(storage.currentFrame)] ~= nil then > storage.buttonStates["lightSelect"] = "on" > else > storage.buttonStates["lightSelect"] = "off" > end 1065,1072c984,991 < --yes, it just checks against a pre-loaded array of the sub-image's pixel values < --at least bmp data is pretty simple to grab < local spectrumPos = button4Position("spectrumPress") < local spectrumIndex = {pos[1]-spectrumPos[1]+1, spectrumPos[4]-pos[2]+1} < if spectrumRGBTable[spectrumIndex[1]][spectrumIndex[2]] ~= nil then < storage.paintColor = convertArraytoRGBA(spectrumRGBTable[spectrumIndex[1]][spectrumIndex[2]]) < self.showSpectrumCursor = {duration, {pos[1]-2, pos[2]-2}} < end --- > --yes, it just checks against a pre-loaded array of the sub-image's pixel values > --at least bmp data is pretty simple to grab > local spectrumPos = button4Position("spectrumPress") > local spectrumIndex = {pos[1]-spectrumPos[1]+1, spectrumPos[4]-pos[2]+1} > if spectrumRGBTable[spectrumIndex[1]][spectrumIndex[2]] ~= nil then > storage.paintColor = convertArraytoRGBA(spectrumRGBTable[spectrumIndex[1]][spectrumIndex[2]]) > self.showSpectrumCursor = {duration, {pos[1]-2, pos[2]-2}} > end 1078,1084c997,1003 < --definitely should have done that dual-use function with these, would be nice, elegant < local RGBA = "" < if RGB[1] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[1]) else RGBA = RGBA..string.format("%x", RGB[1]) end < if RGB[2] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[2]) else RGBA = RGBA..string.format("%x", RGB[2]) end < if RGB[3] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[3]) else RGBA = RGBA..string.format("%x", RGB[3]) end < if storage.paintAlpha < 16 then RGBA = RGBA.."0"..string.format("%x", storage.paintAlpha) else RGBA = RGBA..string.format("%x", storage.paintAlpha) end < return RGBA --- > --definitely should have done that dual-use function with these, would be nice, elegant > local RGBA = "" > if RGB[1] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[1]) else RGBA = RGBA..string.format("%x", RGB[1]) end > if RGB[2] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[2]) else RGBA = RGBA..string.format("%x", RGB[2]) end > if RGB[3] < 16 then RGBA = RGBA.."0"..string.format("%x", RGB[3]) else RGBA = RGBA..string.format("%x", RGB[3]) end > if storage.paintAlpha < 16 then RGBA = RGBA.."0"..string.format("%x", storage.paintAlpha) else RGBA = RGBA..string.format("%x", storage.paintAlpha) end > return RGBA 1088,1091c1007,1010 < return {tonumber(string.sub(rgba,1,2),16), < tonumber(string.sub(rgba,3,4),16), < tonumber(string.sub(rgba,5,6),16), < tonumber(string.sub(rgba,7,8),16)} --- > return {tonumber(string.sub(rgba,1,2),16), > tonumber(string.sub(rgba,3,4),16), > tonumber(string.sub(rgba,5,6),16), > tonumber(string.sub(rgba,7,8),16)} monsters\boss\crystalboss\crystalboss.animation 5c5 < "priority" : 0, --- > "priority" : 1, 21c21 < "priority" : 0, --- > "priority" : 1, 63c63 < "priority" : 0, --- > "priority" : 1, 78,79c78 < "mode" : "transition", < "transition" : "winddown" --- > "mode" : "loop" 164c163 < "zLevel" : 1 --- > "zLevel" : 4 168c167 < "shell" : { --- > "organs" : { 204,211d202 < }, < < "portrait" : { < "portrait" : { < "properties" : { < "image" : ":six.1" < } < } 219c210 < "zLevel" : 2 --- > "zLevel" : 3 244c235 < "image" : ":stage1" --- > "image" : "/monsters/boss/crystalboss/crystal/crystalbossicon.png" 254c245,246 < "zLevel" : 3 --- > "zLevel" : 2, > "offset" : [-0.5, 0.125] 271c263 < "image" : ":attack" --- > "image" : ":fire" 284,291d275 < }, < < "portrait" : { < "portrait" : { < "properties" : { < "image" : ":idle" < } < } 301c285 < "zLevel" : 4 --- > "zLevel" : 1 329c313 < "zLevel" : 4 --- > "zLevel" : 1 357c341 < "zLevel" : 4 --- > "zLevel" : 1 385c369 < "zLevel" : 4 --- > "zLevel" : 1 monsters\boss\crystalboss\idlestate.lua 12a13,15 > function idleState.enteringState(stateData) > end > monsters\boss\crystalboss\skills\crystalbeamattack.lua 8,9c8,12 < timer = 4, < angle = 0 --- > timer = 10, > angleInterval = 10, > angleRange = 1.5, > initialAngle = math.pi / 4, > winddownTimer = 0.33 15d17 < 17a20,22 > entity.setAnimationState("eye", "windup") > > crystalBeamAttack.damagePerSecond = entity.configParameter("crystalBeamAttack.damagePerSecond") 24,25d28 < stateData.timer = stateData.timer + dt < 34c37,48 < local angle = 0.75 * stateData.timer + math.pi/4 --- > local angleFactor = (stateData.timer % stateData.angleInterval) / stateData.angleInterval > local angle = stateData.angleRange * math.sin(angleFactor * math.pi * 2) + stateData.initialAngle > > crystalBeamAttack.rotateBeams(angle, true) > > crystalBeamAttack.spawnProjectiles(angle, crystalBeamAttack.damagePerSecond * dt) > > if stateData.timer < 0 then > entity.setAnimationState("firstBeams", "winddown") > entity.setAnimationState("secondBeams", "winddown") > entity.setAnimationState("eye", "winddown") > end 36c50,51 < crystalBeamAttack.rotateBeams(angle, false) --- > return false > end 37a53,54 > if stateData.winddownTimer > 0 then > stateData.winddownTimer = stateData.winddownTimer - dt 49d65 < 54a71,78 > end > > function crystalBeamAttack.spawnProjectiles(angle, power) > for x = 0, 3 do > local newAngle = angle + math.pi * x * 0.5 > local aimVector = {math.cos(newAngle), math.sin(newAngle)} > world.spawnProjectile("crystalbeamdamage", mcontroller.position(), entity.id(), aimVector, true, {power = power}) > end monsters\boss\crystalboss\skills\crystalbeamattack.monsterskill 8a9 > "damagePerSecond" : 800 objects\generic\torch\torch.object 38a39 > "animationPosition" : [1, 0], 53a55 > "animationPosition" : [1, 0], 68a71 > "animationPosition" : [1, 0], 83a87 > "animationPosition" : [1, 0], 95,98d98 < "animationParts" : { < "bg" : "torch.png", < "fg" : "torchlit.png" < }, 105d104 < "animationPosition" : [1, 0], objects\glitch\medievaltorch\medievaltorch.object 6c6 < "description" : "A simple wooden torch.", --- > "description" : "A solid iron torch with a gentle flickering flame.", 19,20d18 < "statusEffects" : [ ], < 32c30 < "image" : "torch.png:.", --- > "image" : "medievaltorch.png:.", 38a37 > "animationPosition" : [0, 0], 47c46 < "image" : "torchleft.png:.", --- > "image" : "medievaltorchleft.png:.", 53a53 > "animationPosition" : [0, 0], 62c62 < "image" : "torchright.png:.", --- > "image" : "medievaltorchright.png:.", 68a69 > "animationPosition" : [0, 0], 95,98d95 < "animationParts" : { < "bg" : "medievaltorch.png", < "fg" : "medievaltorchlit.png" < }, 105d101 < "animationPosition" : [0, 0], 110c106 < "interactive" : false, --- > // "interactive" : false, objects\mission\lunarbasebunk\lunarbasebunk.object 23c23 < "sitCoverImage" : "/objects/lunarbase/lunarbasebunk/lunarbasebunkcover.png", --- > "sitCoverImage" : "/objects/mission/lunarbasebunk/lunarbasebunkcover.png", objects\outpost\outpostlamp\outpostlamp.frames 6c6 < [ "default.0", "default.off" ] --- > [ "default.on", "default.off" ] 11c11 < "default.default" : "default.off" --- > "default.default" : "default.on" objects\outpost\outpostlamp\outpostlamp.object 18c18 < "imageLayers" : [ { "image" : "outpostlamp.png:.", "fullbright" : true }, { "image" : "outpostlamplit.png:." } ], --- > "image" : "outpostlamp.png:.", 19a20 > 20a22 > 26c28 < "imageLayers" : [ { "image" : "outpostlamp.png:.", "fullbright" : true }, { "image" : "outpostlamplit.png:." } ], --- > "image" : "outpostlamp.png:.", 27a30 > 28a32 > 32c36,58 < ] --- > ], > > "soundEffect" : "/sfx/objects/fluorescent_light_quiet.wav", > > "animation" : "/objects/wired/light/lighttogglebgfullbright.animation", > "animationCustom" : { > "sounds" : { > "on" : [ "/sfx/objects/tinywallswitch.wav" ], > "off" : [ "/sfx/objects/tinywallswitch.wav" ] > } > }, > "animationParts" : { > "bg" : "outpostlamp.png", > "fg" : "outpostlamplit.png" > }, > "animationPosition" : [0, 0], > > "scripts" : [ "/objects/wired/light/light.lua" ], > "scriptDelta" : 60, > > "interactive" : false, > > "inboundNodes" : [ [0, 0] ] objects\outpost\outpostlamp\outpostlamplit.frames 6c6 < [ "default.0", "default.off" ] --- > [ "default.on", "default.off" ] 11c11 < "default.default" : "default.off" --- > "default.default" : "default.on" objects\outpost\outpostlight\outpostlight.frames 5c5 < "dimensions" : [1, 1], --- > "dimensions" : [2, 1], 7c7 < [ "default.0" ] --- > [ "default.on", "default.off" ] 12c12 < "default.default" : "default.0" --- > "default.default" : "default.on" objects\outpost\outpostlight\outpostlight.object 15c15 < "inventoryIcon" : "outpostlight.png", --- > "inventoryIcon" : "outpostlighticon.png", 20,21c20,23 < "frames" : 1, < "animationCycle" : 0.3, --- > "animationPosition" : [0, 0], > > "direction" : "right", > 25c27,40 < ] --- > ], > > "animation" : "/objects/wired/light/lighttogglebgfullbright.animation", > "animationParts" : { > "bg" : "outpostlight.png", > "fg" : "outpostlight.png" > }, > > "scripts" : [ "/objects/wired/light/light.lua" ], > "scriptDelta" : 60, > > "interactive" : false, > > "inboundNodes" : [ [0, 0] ] objects\outpost\outpostmonitor\outpostmonitor.frames 4c4 < "dimensions" : [4, 4], --- > "dimensions" : [5, 1], 6c6 < [ "default.0", "default.1", "default.2", "default.3" ] --- > [ "default.1", "default.2", "default.3", "default.4", "default.off" ] 11c11 < "default.default" : "default.0" --- > "default.default" : "default.off" objects\outpost\outpostmonitor\outpostmonitor.object 25c25 < "imageLayers" : [ { "image" : "outpostmonitor.png:.", "fullbright" : true }, { "image" : "outpostmonitorlit.png:." } ], --- > "image" : "outpostmonitor.png:.", 29,30d28 < "frames" : 4, < "animationCycle" : 0.3, 36c34 < "imageLayers" : [ { "image" : "outpostmonitor.png:.", "fullbright" : true }, { "image" : "outpostmonitorlit.png:." } ], --- > "image" : "outpostmonitor.png:.", 39,40d36 < "frames" : 4, < "animationCycle" : 0.3, 48c44,56 < "soundEffectRadius" : 15 --- > "soundEffectRadius" : 15, > > "animation" : "outpostmonitor.animation", > "animationParts" : { > "bg" : "outpostmonitor.png", > "fg" : "outpostmonitorlit.png" > }, > "animationPosition" : [-16, -8], > > "scripts" : [ "/objects/wired/light/light.lua" ], > "scriptDelta" : 60, > > "inboundNodes" : [ [0, 0] ] objects\outpost\outpostmonitor\outpostmonitorlit.frames 4c4 < "dimensions" : [4, 4], --- > "dimensions" : [5, 1], 6c6 < [ "default.0", "default.1", "default.2", "default.3" ] --- > [ "default.1", "default.2", "default.3", "default.4", "default.off" ] 11c11 < "default.default" : "default.0" --- > "default.default" : "default.off" objects\outpost\outpostsmallmonitor\outpostsmallmonitor.frames 4c4 < "dimensions" : [4, 9], --- > "dimensions" : [5, 1], 6,14c6 < [ "default.0", "default.1", "default.2", "default.3" ], < [ "red.0", "red.1", "red.2", "red.3" ], < [ "blue.0", "blue.1", "blue.2", "blue.3" ], < [ "green.0", "green.1", "green.2", "green.3" ], < [ "yellow.0", "yellow.1", "yellow.2", "yellow.3" ], < [ "orange.0", "orange.1", "orange.2", "orange.3" ], < [ "pink.0", "pink.1", "pink.2", "pink.3" ], < [ "black.0", "black.1", "black.2", "black.3" ], < [ "white.0", "white.1", "white.2", "white.3" ] --- > [ "default.1", "default.2", "default.3", "default.4", "default.off" ] 19,27c11 < "default.default" : "default.0", < "red.default" : "red.0", < "blue.default" : "blue.0", < "green.default" : "green.0", < "yellow.default" : "yellow.0", < "orange.default" : "orange.0", < "pink.default" : "pink.0", < "black.default" : "black.0", < "white.default" : "white.0" --- > "default.default" : "default.off" objects\outpost\outpostsmallmonitor\outpostsmallmonitor.object 25c25 < "imageLayers" : [ { "image" : "outpostsmallmonitor.png:.", "fullbright" : true }, { "image" : "outpostsmallmonitorlit.png:." } ], --- > "image" : "outpostsmallmonitor.png:.", 29,30d28 < "frames" : 4, < "animationCycle" : 0.3, 36c34 < "imageLayers" : [ { "image" : "outpostsmallmonitor.png:.", "fullbright" : true }, { "image" : "outpostsmallmonitorlit.png:." } ], --- > "image" : "outpostsmallmonitor.png:.", 39,41c37 < "frames" : 4, < "animationCycle" : 0.3, < --- > 48c44,56 < "soundEffectRadius" : 15 --- > "soundEffectRadius" : 15, > > "animation" : "outpostsmallmonitor.animation", > "animationParts" : { > "bg" : "outpostsmallmonitor.png", > "fg" : "outpostsmallmonitorlit.png" > }, > "animationPosition" : [-8, -8], > > "scripts" : [ "/objects/wired/light/light.lua" ], > "scriptDelta" : 60, > > "inboundNodes" : [ [0, 0] ] objects\outpost\outpostsmallmonitor\outpostsmallmonitorlit.frames 4c4 < "dimensions" : [4, 9], --- > "dimensions" : [5, 1], 6,14c6 < [ "default.0", "default.1", "default.2", "default.3" ], < [ "red.0", "red.1", "red.2", "red.3" ], < [ "blue.0", "blue.1", "blue.2", "blue.3" ], < [ "green.0", "green.1", "green.2", "green.3" ], < [ "yellow.0", "yellow.1", "yellow.2", "yellow.3" ], < [ "orange.0", "orange.1", "orange.2", "orange.3" ], < [ "pink.0", "pink.1", "pink.2", "pink.3" ], < [ "black.0", "black.1", "black.2", "black.3" ], < [ "white.0", "white.1", "white.2", "white.3" ] --- > [ "default.1", "default.2", "default.3", "default.4", "default.off" ] 19,27c11 < "default.default" : "default.0", < "red.default" : "red.0", < "blue.default" : "blue.0", < "green.default" : "green.0", < "yellow.default" : "yellow.0", < "orange.default" : "orange.0", < "pink.default" : "pink.0", < "black.default" : "black.0", < "white.default" : "white.0" --- > "default.default" : "default.off" objects\outpost\signstore\signdispenser.lua 3c3 < matchingEaselList = world.objectQuery({entity.position()[1]+4,entity.position()[2]},1) --- > matchingEaselList = world.objectQuery({entity.position()[1]-4,entity.position()[2]},1) objects\outpost\signstore\signstoreobject.lua 7c7 < local matchingCabinetList = world.objectQuery({entity.position()[1]-4,entity.position()[2]},1) --- > local matchingCabinetList = world.objectQuery({entity.position()[1]+7,entity.position()[2]},1) 18c18 < if item.name == "Body-customsign" or item.name == "Body-customsigncontainer" then --- > if item.name == "customsign" then projectiles\explosions\coconutexplosion\coconutbreak.config 11c11 < "options" : [ "/sfx/npc/enemydeathpuff.wav" ] --- > "options" : [ "/sfx/projectiles/fire_out_louder.wav" ] projectiles\explosions\healingexplosion\healcloud.config 11c11 < "options" : [ "/sfx/npc/enemydeathpuff.wav" ] --- > "options" : [ "/sfx/projectiles/fire_out_louder.wav" ] projectiles\explosions\poisonsmoke\poisonsmoke.config 11c11 < "options" : [ "/sfx/npc/enemydeathpuff.wav" ] --- > "options" : [ "/sfx/projectiles/fire_out_louder.wav" ] projectiles\minibiomelegendaries\sporecloud\multisporecloud.projectile 41c41 < "options" : [ "/sfx/npc/enemydeathpuff.wav" ] --- > "options" : [ "/sfx/projectiles/fire_out_louder.wav" ] projectiles\minibiomelegendaries\sporecloudx\multisporecloudx.projectile 167c167 < "options" : [ "/sfx/npc/enemydeathpuff.wav" ] --- > "options" : [ "/sfx/projectiles/fire_out_louder.wav" ] treasure\common.treasurepools 920a921,934 > ], > > "microdungeonTechTreasure" : [ > [0, { > "pool" : [ > {"weight" : 0.15, "item" : [ "blanktechcard", 1]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "lightningcoil" } ]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "commonplasmapistol" } ]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "commonplasmamachinepistol" } ]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "commonplasmaassaultrifle" } ]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "commonplasmashotgun" } ]}, > {"weight" : 1.0, "item" : [ "generatedgun", 1, { "definition" : "commonplasmasniperrifle" } ]} > ] > }]