Created
June 6, 2019 00:44
-
-
Save NotMyWing/bc57b8a52917ec0bdfd8432c826b9b6f to your computer and use it in GitHub Desktop.
Have you ever witnessed an eclipse?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Map | |
new: => | |
@map = {} | |
get: (i, j) => | |
if not @map[i] | |
@map[i] = {} | |
@map[i][j] | |
set: (i, j, value) => | |
if not @map[i] | |
@map[i] = {} | |
@map[i][j] = value | |
class Traversable | |
new: (@tile, @x, @y, @objects = {}) => | |
render: => | |
class VPath extends Traversable | |
type: "VPath" | |
tracedOver: false | |
getLeft: => | |
return @tile.cells\get @x, @y - 1 | |
getRight: => | |
return @tile.cells\get @x, @y | |
getTop: => | |
return @tile.intersections\get @x, @y | |
getBottom: => | |
return @tile.intersections\get @x, @y + 1 | |
render: => | |
if @bounds | |
traced = @tile.traceNet.vpaths\get @x, @y | |
color = traced and COLOR_WHITE or COLOR_UNTRACED | |
render.setColor color | |
render.drawRect @bounds.x, @bounds.y, @bounds.width, @bounds.height | |
class HPath extends Traversable | |
type: "HPath" | |
tracedOver: false | |
getLeft: => | |
return @tile.intersections\get @x, @y | |
getRight: => | |
return @tile.intersections\get @x + 1, @y | |
getTop: => | |
return @tile.cells\get @x, @y - 1 | |
getBottom: => | |
return @tile.cells\get @x, @y | |
render: => | |
if @bounds | |
traced = @tile.traceNet.hpaths\get @x, @y | |
color = traced and COLOR_WHITE or COLOR_UNTRACED | |
render.setColor color | |
render.drawRect @bounds.x, @bounds.y, @bounds.width, @bounds.height | |
class Intersection extends Traversable | |
type: "Intersection" | |
hit: (@x, @y) => | |
getLeft: => | |
return @tile.hpaths\get @x - 1, @y | |
getRight: => | |
return @tile.hpaths\get @x, @y | |
getTop: => | |
return @tile.vpaths\get @x, @y - 1 | |
getBottom: => | |
return @tile.vpaths\get @x, @y | |
render: => | |
if @bounds | |
traced = @tile.traceNet.intersections\get @x, @y | |
color = traced and COLOR_WHITE or COLOR_UNTRACED | |
skipDraw = false | |
for k, v in pairs @objects | |
render.setColor color | |
skipDraw = skipDraw or (v\render pmin, barWidth) | |
shouldDraw = if traced | |
true | |
elseif not skipDraw | |
sum = (@getTop! and 1 or 0) + | |
(@getBottom! and 1 or 0) + | |
(@getLeft! and 1 or 0) + | |
(@getRight! and 1 or 0) | |
sum < 3 | |
else | |
false | |
if shouldDraw | |
render.setColor color | |
drawCircleRect @bounds.x, @bounds.y, @bounds.width | |
class Cell extends Traversable | |
type: "Cell" | |
getLeft: => | |
return @tile.vpaths\get @x, @y | |
getRight: => | |
return @tile.vpaths\get @x + 1, @y | |
getTop: => | |
return @tile.hpaths\get @x, @y | |
getBottom: => | |
return @tile.hpaths\get @x, @y + 1 | |
class Rect | |
new: (@x, @y, @width, @height) => | |
contains: (x, y) => | |
return x > @x and | |
y > @y and | |
x < @x + @width and | |
y < @y + @height | |
class Object | |
new: (@parent, @attributes) => | |
check: => | |
render: => | |
class IntersectionObject_Entrance extends Object | |
new: (@parent, @attributes) => | |
super @parent, @attributes | |
parentBounds = @parent.bounds | |
w = parentBounds.width * 2.5 | |
h = parentBounds.height * 2.5 | |
x = parentBounds.x + (parentBounds.width / 2) - w / 2 | |
y = parentBounds.y + (parentBounds.width / 2) - h / 2 | |
@bounds = Rect x, y, w, h | |
render: => | |
if @bounds | |
drawCircleRect @bounds.x, @bounds.y, @bounds.width | |
return true | |
class IntersectionObject_Exit extends Object | |
render: => | |
bounds = @parent.bounds | |
if bounds | |
dir = @attributes.direction | |
width = bounds.width | |
render.drawRect bounds.x + (dir.x * width * 0.5), | |
bounds.y + (dir.y * width * 0.5), | |
width, | |
width | |
drawCircle bounds.x + (dir.x * width) + (width / 2), bounds.y + (dir.y * width) + (width / 2), width / 2 | |
return true | |
INTERSECTION_OBJECTS = { | |
"Entrance": IntersectionObject_Entrance, | |
"Exit": IntersectionObject_Exit | |
} | |
--------------------------------------- | |
-- TILE DEFINITION -- | |
--------------------------------------- | |
export INNERAREA_SCALE = (630-180) / 630 | |
export BARWIDTH_RATIO = 8 | |
export MIN_BARWIDTH = 8 | |
if SERVER | |
export BLIP_SOUND = sounds.create chip!, "buttons/blip1.wav" | |
export ERROR_SOUND = sounds.create chip!, "buttons/combine_button_locked.wav" | |
if CLIENT | |
export MATERIAL_CIRCLE_1 = material.load "vgui/hud/800corner1" | |
export MATERIAL_CIRCLE_2 = material.load "vgui/hud/800corner2" | |
export MATERIAL_CIRCLE_3 = material.load "vgui/hud/800corner4" | |
export MATERIAL_CIRCLE_4 = material.load "vgui/hud/800corner3" | |
export COLOR_BG = Color 80, 77, 255, 255 | |
export COLOR_UNTRACED = Color 40, 22, 186 | |
export COLOR_WHITE = Color 255, 255, 255, 255 | |
export COLOR_VIGNETTE = Color 0, 0, 0, 92 | |
export MATERIAL_VIGNETTE = material.load "gmod/scope" | |
export drawCircle = (x, y, r) -> | |
render.setMaterial MATERIAL_CIRCLE_1 | |
render.drawTexturedRect x - r, y - r, r, r | |
render.setMaterial MATERIAL_CIRCLE_2 | |
render.drawTexturedRect x, y - r, r, r | |
render.setMaterial MATERIAL_CIRCLE_3 | |
render.drawTexturedRect x - r, y, r, r | |
render.setMaterial MATERIAL_CIRCLE_4 | |
render.drawTexturedRect x, y, r, r | |
export drawCircleRect = (x, y, width) -> | |
halfW = width / 2 | |
render.setMaterial MATERIAL_CIRCLE_1 | |
render.drawTexturedRect x, y, halfW, halfW | |
render.setMaterial MATERIAL_CIRCLE_2 | |
render.drawTexturedRect x + halfW, y, halfW, halfW | |
render.setMaterial MATERIAL_CIRCLE_3 | |
render.drawTexturedRect x, y + halfW, halfW, halfW | |
render.setMaterial MATERIAL_CIRCLE_4 | |
render.drawTexturedRect x + halfW, y + halfW, halfW, halfW | |
if SERVER | |
export class TraceNet | |
clearTraversables: () => | |
@vpaths = Map! | |
@hpaths = Map! | |
@intersections = Map! | |
new: () => | |
@clearTraversables! | |
isTraced: (any) => | |
if not any or any.type == "Cell" | |
return false | |
t = switch any.type | |
when "VPath" | |
@vpaths | |
when "HPath" | |
@hpaths | |
when "Intersection" | |
@intersections | |
return t\get any.x, any.y | |
netUpdate: (action, type, i, j) => | |
net.start "UpdateTraversable" | |
net.writeString action | |
net.writeString type | |
net.writeInt i, 8 | |
net.writeInt j, 8 | |
net.send! | |
addTracedVPath: (i, j) => | |
@vpaths\set i, j, true | |
@netUpdate "add", "vpath", i, j | |
addTracedHPath: (i, j) => | |
@hpaths\set i, j, true | |
@netUpdate "add", "hpath", i, j | |
addTracedIntersection: (i, j) => | |
@intersections\set i, j, true | |
@netUpdate "add", "intersection", i, j | |
removeTracedVPath: (i, j) => | |
@vpaths\set i, j, false | |
@netUpdate "remove", "vpath", i, j | |
removeTracedHPath: (i, j) => | |
@hpaths\set i, j, false | |
@netUpdate "remove", "hpath", i, j | |
removeTracedIntersection: (i, j) => | |
@intersections\set i, j, false | |
@netUpdate "remove", "intersection", i, j | |
trace: (any) => | |
add = switch any.type | |
when "VPath" | |
@.addTracedVPath | |
when "HPath" | |
@.addTracedHPath | |
when "Intersection" | |
@.addTracedIntersection | |
add @, any.x, any.y | |
unTrace: (any) => | |
remove = switch any.type | |
when "VPath" | |
@.removeTracedVPath | |
when "HPath" | |
@.removeTracedHPath | |
when "Intersection" | |
@.removeTracedIntersection | |
remove @, any.x, any.y | |
clearTracedTraversables: () => | |
@clearTraversables! | |
net.start "ClearTraversables" | |
net.send! | |
else | |
export class TraceNet | |
clearTraversables: () => | |
@vpaths = Map! | |
@hpaths = Map! | |
@intersections = Map! | |
new: () => | |
@clearTraversables! | |
net.receive "ClearTraversables", () -> | |
@clearTraversables! | |
net.receive "UpdateTraversable", () -> | |
action = net.readString! | |
type = net.readString! | |
i = net.readInt 8 | |
j = net.readInt 8 | |
t = switch type | |
when "vpath" | |
@vpaths | |
when "hpath" | |
@hpaths | |
when "intersection" | |
@intersections | |
printTable {action, type, i, j} | |
t\set i, j, (action == "add") and true or false | |
class Tile | |
screenWidth: 512 | |
screenHeight: 512 | |
render: => | |
render.clear COLOR_BG, true | |
render.setColor COLOR_BG | |
render.drawRect 0, 0, @screenWidth, @screenHeight | |
stretch = 92 | |
render.setColor COLOR_VIGNETTE | |
render.setMaterial MATERIAL_VIGNETTE | |
render.drawTexturedRect -stretch * 2, -stretch, self.screenWidth + stretch * 4, self.screenHeight + stretch * 1.8 | |
render.setMaterial! | |
render.setColor COLOR_UNTRACED | |
for j = 1, @height + 1 | |
for i = 1, @width | |
hpath = @hpaths\get i, j | |
if hpath | |
hpath\render! | |
for j = 1, @height | |
for i = 1, @width + 1 | |
vpath = @vpaths\get i, j | |
if vpath | |
vpath\render! | |
for j = 1, @height + 1 | |
for i = 1, @width + 1 | |
int = @intersections\get i, j | |
if int | |
int\render! | |
initClient: => | |
hook.add "render", "render", () -> | |
@render! | |
timer.create "pollCursor", 0.1, 0, () -> | |
@pollCursor! | |
pollCursor: => | |
x, y = render.cursorPos player! | |
if x and y | |
net.start "pollCursor" | |
net.writeFloat x | |
net.writeFloat y | |
net.send "server", true | |
-- SERVER | |
initServer: => | |
hook.add "PlayerUse", "PlayerUse", (ply, ent) -> | |
@use ply, ent | |
@cursors = {} | |
net.receive "pollCursor", (len, ply) -> | |
x = net.readFloat! | |
y = net.readFloat! | |
@cursors[ply] = { :x, :y } | |
-- SERVER | |
think: => | |
-- SERVER | |
seekOnce: (x, y) => | |
objects = {} | |
for j = 1, @height + 1 | |
for i = 1, @width + 1 | |
int = @intersections\get i, j | |
shouldReturn = false | |
for k, v in pairs int.objects | |
if v.bounds and v.bounds\contains x, y | |
shouldReturn = true | |
break | |
if shouldReturn or int.bounds\contains x, y | |
return int | |
for j = 1, @height + 1 | |
for i = 1, @width | |
hpath = @hpaths\get i, j | |
if hpath.bounds\contains x, y | |
return hpath | |
for j = 1, @height | |
for i = 1, @width + 1 | |
vpath = @vpaths\get i, j | |
if vpath.bounds\contains x, y | |
return vpath | |
return traversables, objects | |
-- SERVER | |
seekThrough: (x, y) => | |
traversables = {} | |
objects = {} | |
for j = 1, @height + 1 | |
for i = 1, @width | |
hpath = @hpaths\get i, j | |
if hpath.bounds\contains x, y | |
table.insert traversables, hpath | |
for j = 1, @height | |
for i = 1, @width + 1 | |
vpath = @vpaths\get i, j | |
if vpath.bounds\contains x, y | |
table.insert traversables, vpath | |
for j = 1, @height + 1 | |
for i = 1, @width + 1 | |
int = @intersections\get i, j | |
if int.bounds\contains x, y | |
table.insert traversables, int | |
for k, v in pairs int.objects | |
if v.bounds and v.bounds\contains x, y | |
table.insert objects, v | |
return traversables, objects | |
-- SERVER | |
puzzleStart: (ply, entrance) => | |
@traceNet\clearTracedTraversables! | |
@traceNet\addTracedIntersection entrance.parent.x, entrance.parent.y | |
-- SERVER | |
puzzleStop: => | |
timer.remove "useStop" | |
@isBeingUsedBy = nil | |
BLIP_SOUND\stop! | |
BLIP_SOUND\play! | |
puzzleThink: => | |
tv = @seekOnce @cursors[@isBeingUsedBy].x, @cursors[@isBeingUsedBy].y | |
if tv and tv.type ~= "Cell" and not @traceNet\isTraced tv | |
anyNeighborTraced = (@traceNet\isTraced tv\getLeft!) or | |
(@traceNet\isTraced tv\getRight!) or | |
(@traceNet\isTraced tv\getTop!) or | |
(@traceNet\isTraced tv\getBottom!) | |
if anyNeighborTraced | |
@traceNet\trace tv | |
-- SERVER | |
use: (ply, ent) => | |
if (@isBeingUsedBy ~= nil) and @isBeingUsedBy ~= ply | |
@puzzleStop! | |
if ply and not @isBeingUsedBy and @cursors[ply] | |
tv, objects = @seekThrough @cursors[ply].x, @cursors[ply].y | |
for k, v in pairs objects | |
if v.attributes and v.attributes.type == "Entrance" | |
@isBeingUsedBy = ply | |
return @puzzleStart ply, v | |
elseif @isBeingUsedBy | |
@puzzleThink! | |
timer.remove "useStop" | |
timer.create "useStop", 0.15, 1, () -> | |
@puzzleStop! | |
-- SHARED | |
new: (@width = 1, @height = 1, cells = {}, vpaths = {}, hpaths = {}, intersections = {}) => | |
@traceNet = TraceNet! | |
innerArea = @screenWidth * INNERAREA_SCALE | |
cellsMax = math.max @width, @height | |
barWidth = math.max MIN_BARWIDTH, (innerArea / (BARWIDTH_RATIO * cellsMax)) | |
bar = (innerArea - (barWidth * (cellsMax + 1))) / cellsMax | |
offsetH = (@screenWidth - (barWidth * (@width + 1)) - (bar * @width)) / 2 | |
offsetV = (@screenWidth - (barWidth * (@height + 1)) - (bar * @height)) / 2 | |
@cells = Map! | |
for j = 1, @height | |
for i = 1, @width | |
@cells\set i, j, Cell @, i, j | |
@hpaths = Map! | |
for j = 1, @height + 1 | |
for i = 1, @width | |
hpath = HPath @, i, j | |
x = offsetH + (barWidth / 2) + (i - 1) * (bar + barWidth) | |
y = offsetV + (j - 1) * (bar + barWidth) | |
hpath.bounds = Rect x, y, bar + barWidth, barWidth | |
@hpaths\set i, j, hpath | |
@vpaths = Map! | |
for j = 1, @height | |
for i = 1, @width + 1 | |
vpath = VPath @, i, j | |
y = offsetV + (barWidth / 2) + (j - 1) * (bar + barWidth) | |
x = offsetH + (i - 1) * (bar + barWidth) | |
vpath.bounds = Rect x, y, barWidth, bar + barWidth | |
@vpaths\set i, j, vpath | |
@intersections = Map! | |
for j = 1, @height + 1 | |
for i = 1, @width + 1 | |
int = Intersection @, i, j | |
x = offsetH + (i - 1) * (bar + barWidth) | |
y = offsetV + (j - 1) * (bar + barWidth) | |
int.bounds = Rect x, y, barWidth, barWidth | |
@intersections\set i, j, int | |
for k, v in pairs intersections | |
int = @intersections\get v.x, v.y | |
obj = INTERSECTION_OBJECTS[v.type] int | |
obj.attributes = v.attributes or {} | |
obj.attributes.type = v.type | |
table.insert int.objects, obj | |
if CLIENT | |
@initClient! | |
if SERVER | |
@initServer! | |
intersections = { | |
{ | |
x: 1, | |
y: 4, | |
type: "Entrance" | |
}, | |
{ | |
x: 4, | |
y: 1, | |
type: "Exit", | |
attributes: { | |
direction: { | |
x: 0, | |
y: -1 | |
} | |
} | |
} | |
} | |
tile = Tile 3, 3, {}, {}, {}, intersections |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment