Skip to content

Instantly share code, notes, and snippets.

@NotMyWing
Last active October 6, 2018 14:43
Show Gist options
  • Save NotMyWing/dc2ab7807cbf189c1c1085603229116d to your computer and use it in GitHub Desktop.
Save NotMyWing/dc2ab7807cbf189c1c1085603229116d to your computer and use it in GitHub Desktop.
StarfallEx Mooncopter
--@name Mooncopter
--@server
--@model models/squad/sf_plates/sf_plate3x3.mdl
-- Please compile it yourself.
-- Either download the moon compiler,
-- or https://moonscript.org/compiler/
-- don't forget to copy and paste the directives above
-- no dumb zone
if CLIENT
return
sign = (value) ->
(value > 0) and 1 or ((value < 0) and -1 or 0)
clamp = (value, min, max) ->
(value < min) and min or ((value > max) and max or value)
class Thruster
thrust: 0
new: (t) =>
with t
@func = .func
@rate = .rate or 1.05
@max = .max or 256
@punch = .punch or 8
@decay = .decay or 0.85
@decayTreshold = .decayTreshold or 2
accelerate: (dir) =>
if dir == 0
return
dir = sign dir
current = @thrust or 0
if sign(current) ~= dir
if sign(current) ~= 0
return
else
current = dir * @punch
@thrust = clamp current * @rate, -@max, @max
@accelerating = true
think: =>
if not @accelerating
if math.abs(@thrust) > @decayTreshold
@thrust *= @decay
else
@thrust = 0
else
@accelerating = false
if @func and @thrust ~= 0
@.func @thrust
class PodCamDriver
new: (@drone) =>
think: =>
if isValid @wirelink
pod = @drone.drivers.Pod
@wirelink.Activated = (pod and isValid pod\getDriver!) and 1 or 0
adjustInput: (@wirelink) =>
if isValid @wirelink
@wirelink.Parent = @drone.entity
@wirelink.Position = @drone.center
class PodDriver
getDriver: =>
if isValid @wirelink
if isValid @wirelink.Driver
return @wirelink.Driver
else
return @wirelink\entity!\getDriver!
else
return
new: (@drone) =>
think: =>
if isValid @wirelink
driver = @getDriver!
if isValid driver
linear = (driver\keyDown IN_KEY.FORWARD) and 1 or 0
linear -= (driver\keyDown IN_KEY.BACK) and 1 or 0
if (@drone.thrusters.linear)
@drone.thrusters.linear\accelerate linear
angular = (driver\keyDown IN_KEY.MOVELEFT) and 1 or 0
angular -= (driver\keyDown IN_KEY.MOVERIGHT) and 1 or 0
if (@drone.thrusters.angular)
@drone.thrusters.angular\accelerate angular
vertical = (driver\keyDown IN_KEY.JUMP) and 1 or 0
vertical -= (driver\keyDown IN_KEY.SPEED) and 1 or 0
if (@drone.thrusters.vertical)
@drone.thrusters.vertical\accelerate vertical
adjustInput: (@wirelink) =>
peripheralAngleCompat =
"models/jaanus/wiretool/wiretool_range.mdl": Angle 90, 0, 0
"models/jaanus/wiretool/wiretool_siren.mdl": Angle 90, 0, 0
"models/jaanus/wiretool/wiretool_beamcaster.mdl": Angle 90, 0, 0
class FirePeripheralDriver
defaultPeripheralAngle:
Angle 0, 0, 0
new: (@drone, @position, @key) =>
think: =>
pod = @drone.drivers.Pod
if (isValid @wirelink) and pod
driver = pod\getDriver!
if isValid driver
@wirelink.A = (driver\keyDown @key) and 1 or 0
@wirelink.Fire = (driver\keyDown @key) and 1 or 0
adjustInput: (wirelink) =>
if isValid @wirelink
if isValid @wirelink\entity!
constraint.breakAll @wirelink\entity!
@wirelink = wirelink
if isValid @wirelink
ent = @wirelink\entity!
timer.simple 0.5, () ->
if isValid(ent) and isValid(@drone.entity)
model = ent\getModel!
angle = if peripheralAngleCompat[model]
peripheralAngleCompat[model]
else
@defaultPeripheralAngle
with ent
\setPos @drone\toWorld @position
\setAngles @drone\toWorld angle
constraint.weld @drone.entity, ent
constraint.nocollide @drone.entity, ent
class LeftFirePeripheralDriver extends FirePeripheralDriver
new: (@drone) =>
super @drone, Vector(30, 28, -6), IN_KEY.ATTACK
class RightFirePeripheralDriver extends FirePeripheralDriver
new: (@drone) =>
super @drone, Vector(30, 8, -6), IN_KEY.ATTACK2
class CosmeticWorker
white:
Color 255
new: (@drone) =>
think: =>
@drone.entity\setColor @drone.entity\getColor!\setA(0)
maxSpeed = math.max unpack(for k, v in pairs @drone.thrusters
math.abs v.thrust
)
i = 0
for k, v in pairs @drone.corners
i += 1
pitch = clamp @drone.thrusters.linear.thrust , -90, 90
angular = clamp @drone.thrusters.angular.thrust, -90, 90
roll = 0
-- Rotate either the third or the second turbine, sign-depending
if (i == 3 and angular > 0) or (i == 2 and angular < 0)
roll = angular
color = (@white * math.max maxSpeed / 64, 0.25)\setA 192
v.holo\setAngles @drone\toWorld Angle(pitch, 0, roll)
v.innerCircle\setColor color
class EngineToggleWorker
new: (@drone) =>
think: =>
if @wireInput == 1
if @drone\getEngine!
@drone\setEngine false
return
pod = @drone.drivers.Pod
if pod
driver = pod\getDriver!
if isValid driver
keyPressed = driver\keyDown IN_KEY.RELOAD
if keyPressed and @shouldChange
@shouldChange = false
@drone\setEngine not @drone\getEngine!
elseif not keyPressed and not @shouldChange
@shouldChange = true
input:
name: "EngineOff",
type: "Number"
adjustInput: (@wireInput) =>
class Drone
corners:
upLeft: Vector(6, 6),
upRight: Vector(6, 30),
downLeft: Vector(30, 6),
downRight: Vector(30, 30)
center:
Vector 18, 18
sounds:
{}
thrusters:
{}
controls:
{}
drivers:
PodCamera: PodCamDriver,
Pod: PodDriver,
LeftFirePeripheral: LeftFirePeripheralDriver
RightFirePeripheral: RightFirePeripheralDriver
workers:
Cosmetic: CosmeticWorker,
EngineToggle: EngineToggleWorker
toWorld: (value) =>
if type(value) == "Angle"
@entity\localToWorldAngles value
elseif type(value) == "Vector"
@entity\localToWorld value
adjustInputs: (key, value) =>
if @drivers[key] and @drivers[key].adjustInput
@drivers[key]\adjustInput value
for k, v in pairs @workers
if v.input and ((not v.input.name and key == k) or key == v.input.name)
v\adjustInput value
createHolograms: =>
for k, v in pairs @corners
v.holo = holograms.create(
@toWorld(v - Vector(0, 0, 0.5)),
@toWorld(Angle(0, 0, 0)),
"models/props_phx/construct/metal_wire1x1.mdl",
Vector(0.25)
)
v.holo\setParent @entity
v.innerCircle = holograms.create(
@toWorld(v - Vector(0, 0, 0.4)),
@toWorld(Angle(0, 0, 0)),
"models/props_phx/construct/metal_wire1x1.mdl",
Vector(0.22)
)
v.innerCircle\setMaterial "debug/debugdrawflat"
v.innerCircle\setParent v.holo
v.cube = holograms.create(
@toWorld(v - Vector(0, 0, 0)),
@toWorld(Angle(0, 0, 0)),
"models/hunter/blocks/cube025x025x025.mdl",
Vector(0.525)
)
v.cube\setMaterial "models/props_combine/com_shield001a"
v.cube\setParent @entity
v.cube\setTrails 8, 0, 0.2, "trails/plasma", Vector(128), 0, true
v.cube\setAngVel Angle(0, 45 + math.random(-10, 10), 45 + math.random(-10, 10))
-- Build the inner model
for i = 1, 8 do
holo = holograms.create(
@toWorld(Vector(18, 18)),
@toWorld(Angle(0, i * 90, (i <= 4) and 0 or 180)),
"models/phxtended/trieq1x1x1solid.mdl",
Vector(0.25, 0.25, 0.1)
)
holo\setParent @entity
-- Battery box
batbox = holograms.create(
@toWorld(Vector(6, 18, 0))
@toWorld(Angle())
"models/hunter/blocks/cube025x025x025.mdl"
Vector(0.6, 0.6, 0.4)
)
batbox\setMaterial "phoenix_storms/metalset_1-2"
batbox\setParent @entity
createThrusters: =>
with @thrusters
.vertical = Thruster
rate: 1.035,
max: 256,
punch: 8,
func: (thrust)->
if @getEngine!
vec = Vector(0, 0, 1) * thrust * @entity\getMass!
@entity\applyForceCenter vec
.linear = Thruster
rate: 1.03,
func: (thrust)->
if @getEngine!
yaw = math.rad @entity\getAngles!.y
x = math.cos yaw
y = math.sin yaw
vec = Vector(x, y, 0) * thrust * @entity\getMass!
@entity\applyForceCenter vec
.angular = Thruster
rate: 1.04,
max: 128,
func: (thrust)->
if @getEngine!
ang = Angle(0, thrust * @entity\getMass!, 0)
@entity\applyAngForce ang
think: =>
for k, v in pairs @thrusters
v\think!
for k, v in pairs @drivers
if isValid(v.wirelink) and v.think
v\think!
for k, v in pairs @workers
if v.think
v\think!
if @getEngine!
-- Simulate air friction
mult = 0.25
@entity\applyForceCenter -@entity\getVelocity! * mult * @entity\getMass!
-- Negate angular speed
@entity\applyAngForce -@entity\getAngleVelocityAngle! * 0.7 * @entity\getMass!
-- Stabilize
ang = (Angle() - @entity\getAngles!)\setY 0
@entity\applyAngForce ang * 0.8 * @entity\getMass!
setupIO: =>
inputs = {}
inputsTypes = {}
for k, v in pairs @drivers
table.insert inputs, k
table.insert inputsTypes, "Wirelink"
for k, v in pairs @workers
if v.input
table.insert inputs, v.input.name or k
table.insert inputsTypes, v.input.type or "Number"
wire.adjustInputs inputs, inputsTypes
setupSounds: =>
with @sounds
with .ambient = sounds.create @entity, "ambient/machines/wall_loop1.wav"
\setVolume 0.6
\setSoundLevel 50
\play!
with .click = sounds.create @entity, "NPC_CombineCamera.Click"
\setVolume 0.6
\setSoundLevel 80
setEngine: (state) =>
if (@__engineState ~= state)
@__engineState = state
if state
for k, v in pairs @drivers
if v.engineStart
v\engineStart!
for k, v in pairs @workers
if v.engineStart
v\engineStart!
with @entity
\setFrozen false
\enableGravity false
\setNoDraw true
\setMass 20000
\enableDrag false
if @sounds.ambient
@sounds.ambient\setVolume 1, 0.25
for k, v in pairs @corners
v.cube\setNoDraw false
else
for k, v in pairs @drivers
if v.engineStop
v\engineStop!
for k, v in pairs @workers
if v.engineStop
v\engineStop!
with @entity
\setFrozen false
\enableGravity true
\setNoDraw true
\setMass 1
\enableDrag true
if @sounds.ambient
@sounds.ambient\setVolume 0, 1
for k, v in pairs @corners
v.cube\setNoDraw true
v.innerCircle\setColor Color 0
getEngine: =>
@__engineState
new: =>
@entity = chip!
-- Initialize driver classes
for k, driver in pairs @drivers
@drivers[k] = driver @
-- Initialize worker classes
for k, worker in pairs @workers
@workers[k] = worker @
-- Initialize holograms
@createHolograms!
-- Initialize thrusters
@createThrusters!
-- Setup wire input/output
@setupIO!
-- Initialize drone input adjustments
hook.add "input", "droneInputs", (key, value) ->
@adjustInputs key, value
-- Setup the drone with a slight delay
timer.simple 0.25, () ->
-- Setup sounds
@setupSounds!
@setEngine true
-- Initialize thinker
hook.add "think", "droneThink", () ->
@think!
drone = Drone!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment