Last active
October 6, 2018 14:43
-
-
Save NotMyWing/dc2ab7807cbf189c1c1085603229116d to your computer and use it in GitHub Desktop.
StarfallEx Mooncopter
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
--@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