Skip to content

Instantly share code, notes, and snippets.

@NotMyWing
Created June 6, 2019 00:44
Show Gist options
  • Save NotMyWing/bc57b8a52917ec0bdfd8432c826b9b6f to your computer and use it in GitHub Desktop.
Save NotMyWing/bc57b8a52917ec0bdfd8432c826b9b6f to your computer and use it in GitHub Desktop.
Have you ever witnessed an eclipse?
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