-- v1.3.0 local jewel = {} local redstone = require("redstone") local npcManager = require("npcManager") local npcutils = require("npcs/npcutils") local lineguide = require("lineguide") local min = math.min local insert, remove = table.insert, table.remove local split, trim = string.split, string.trim jewel.name = "jewel" jewel.id = NPC_ID jewel.order = 0.68 jewel.config = npcManager.setNpcSettings({ id = jewel.id, width = 32, height = 32, gfxwidth = 32, gfxheight = 32, gfxoffsetx = 0, gfxoffsety = 0, frames = 1, framespeed = 8, framestyle = 0, invisible = false, mute = false, jumphurt = false, noblockcollision = true, spinjumpsafe = false, nogravity = true, notcointransformable = true, nohurt = true, noyoshi = true, disabledespawn = false, lightningframes = 3, -- The amount of frames in the lightning image lightningframespeed = 2, -- The framespeed for the lightning animation lightningthickness = -1, -- Set -1 for random, otherwise use this value }) npcManager.registerHarmTypes(jewel.id, {HARM_TYPE_JUMP, HARM_TYPE_SPINJUMP}, {[HARM_TYPE_JUMP] = 10, [HARM_TYPE_SPINJUMP] = 10}) lineguide.registerNpcs(jewel.id) local ilightning = Graphics.loadImage(Misc.resolveFile("npc-"..jewel.id.."-1.png")) local rayWidth, rayHeight = ilightning.width, ilightning.height/jewel.config.lightningframes local sfxpower = Audio.SfxOpen(Misc.resolveFile("ampedjewel-powered.ogg")) local sfxjump = 2 local jewid = 0 local reset = {} local rays = {} local function shareval(t1, t2) for i = 1, #t1 do for j = 1, #t2 do if t1[i] == t2[j] then return true end end end end local function tableMultiInsert(tbl,tbl2) for _, v in ipairs(tbl2) do insert(tbl, v) end end function jewel.prime(n) local data = n.data data.animFrame = data.animFrame or 0 data.animTimer = data.animTimer or 0 data.frameX = data._settings.type or 0 data.frameY = data.frameY or 0 jewid = jewid + 1 data.index = data.inedx or jewid data.active = data.ective or false data.connections = {} local tagstext = split(data._settings.tagstext, ",") data.pins = {} for i = 1, #tagstext do data.pins[i] = trim(tagstext[i]) end data.lightAnimFrame = data.lightAnimFrame or 0 data.lightAnimTimer = data.lightAnimTimer or 0 data.lightThickness = data.lightThickness or RNG.random(1, 2) data.hitbox = Colliders.Circle(0, 0, 1000) end function jewel.onRedTick(n) local data = n.data data.observ = false if reset then rays = {} reset = false end if data.power == 0 then data.frameY = 0 else data.frameY = 1 data.hitbox.x, data.hitbox.y = n.x + 0.5*n.width, n.y + 0.5*n.height if n.data.pins[1] ~= "" then for _, npc in ipairs(Colliders.getColliding{a = data.hitbox, b = jewel.id, btype = Colliders.NPC, filter = function(npc) return n ~= npc and (not npc.data.connections[n.data.index]) and (npc.data.power > 0 or npc.data.powerPrev > 0) and shareval(n.data.pins, npc.data.pins) end}) do npc.data.active = true n.data.active = true n.data.connections[npc.data.index] = true insert(rays, {startNPC = n, stopNPC = npc, frame = data.lightAnimFrame, thickness = data.lightThickness}) end end if data.powerPrev == 0 and redstone.onScreenSound(n) then SFX.play(sfxpower) end end if (data.power ~= 0 and data.powerPrev == 0) or (data.power == 0 and data.powerPrev ~= 0) then data.observ = true end data.lightAnimTimer = data.lightAnimTimer + 1 if data.lightAnimTimer >= jewel.config.lightningframespeed then data.lightAnimTimer = 0 data.lightAnimFrame = data.lightAnimFrame + 1 if data.lightAnimFrame >= jewel.config.lightningframes then data.lightAnimFrame = 0 end end redstone.resetPower(n) end function jewel.onTick() local playerList = Player.get() for i = #rays, 1, -1 do local ray = rays[i] if not (ray.startNPC and ray.stopNPC) and not (ray.startNPC.isValid and ray.stopNPC.isValid) then remove(rays, i) else local start = vector(ray.startNPC.x + 0.5*ray.startNPC.width, ray.startNPC.y + 0.5*ray.startNPC.height) local stop = vector(ray.stopNPC.x + 0.5*ray.stopNPC.width, ray.stopNPC.y + 0.5*ray.stopNPC.height) for k, p in ipairs(playerList) do if Colliders.linecast(start, stop, p) then p:harm() end end end end end function jewel.onRedTickEnd(n) n.data.connections = {} n.data.active = false reset = true end jewel.onRedDraw = redstone.drawNPC local function drawRay(start, stop, frame, thickness) local p = -45 if jewel.config.foreground then p = -15 end if jewel.config.lightningthickness ~= -1 then thickness = jewel.config.lightningthickness end local lenght = (start - stop).length local vertexCoords,textureCoords = {}, {} local direction = (stop - start):normalize() local lineWidth = thickness*direction:rotate(90)*rayHeight/jewel.config.lightningframes local texX, texY, texH = (1 - (1.8*lunatime.tick() % rayWidth)/rayWidth), frame/jewel.config.lightningframes, (frame + 1)/jewel.config.lightningframes local segment = start local j = 0 while j < lenght do local segmentLength = math.min(lenght - j, (1 - texX)*rayWidth) local texW = segmentLength/rayWidth + texX local y = direction*segmentLength local z1, z2, z3, z4 = segment + lineWidth, segment - lineWidth, segment + y + lineWidth, segment + y - lineWidth tableMultiInsert(vertexCoords, {z1.x, z1.y, z2.x, z2.y, z4.x, z4.y, z1.x, z1.y, z3.x, z3.y, z4.x, z4.y}) tableMultiInsert(textureCoords,{texX, texY, texX, texH, texW, texH, texX, texY, texW, texY, texW, texH}) texX = 0 segment = segment + y j = j + segmentLength end Graphics.glDraw{texture = ilightning, vertexCoords = vertexCoords,textureCoords = textureCoords, priority = p - 0.01, sceneCoords = true} end -- Huge Thanks to Mr.DoubleA for helping me getting this to work! function jewel.onDraw() if jewel.config.invisible then return end local p = -45 if jewel.config.foreground then p = -15 end for i = #rays, 1, -1 do local ray = rays[i] if (ray.startNPC and ray.stopNPC) and (ray.startNPC.isValid and ray.stopNPC.isValid) then local start = vector.v2(ray.startNPC.x + 0.5*ray.startNPC.width, ray.startNPC.y + 0.5*ray.startNPC.height) local stop = vector.v2(ray.stopNPC.x + 0.5*ray.stopNPC.width, ray.stopNPC.y + 0.5*ray.stopNPC.height) drawRay(start, stop, ray.frame, ray.thickness) else remove(rays, i) end end end function jewel.onNPCHarm(event, n, reason, culprit) if n.id == jewel.id and (reason == HARM_TYPE_JUMP or reason == HARM_TYPE_SPINJUMP) then SFX.play(sfxjump) if n.data.power > 0 or n.data.powerPrev > 0 then culprit:harm() end event.cancelled = true end end function jewel.onInitAPI() registerEvent(jewel, "onNPCHarm", "onNPCHarm") registerEvent(jewel, "onTick", "onTick") registerEvent(jewel, "onDraw", "onDraw") end redstone.register(jewel) return jewel