diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 6813fcb9..57233005 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,5 +1,7 @@ package src; +import shapes.Nuke; +import shapes.Magnet; import src.Replay; import hxd.impl.Air3File.FileSeek; import gui.Canvas; @@ -594,10 +596,14 @@ class MarbleWorld extends Scheduler { shape = new DuctFan(); else if (dataBlockLowerCase == "smallductfan") shape = new SmallDuctFan(); + else if (dataBlockLowerCase == "magnet") + shape = new Magnet(); else if (dataBlockLowerCase == "antigravityitem") shape = new AntiGravity(cast element); else if (dataBlockLowerCase == "landmine") shape = new LandMine(); + else if (dataBlockLowerCase == "nuke") + shape = new Nuke(); else if (dataBlockLowerCase == "shockabsorberitem") shape = new ShockAbsorber(cast element); else if (dataBlockLowerCase == "superspeeditem") @@ -672,10 +678,14 @@ class MarbleWorld extends Scheduler { shape = new DuctFan(); else if (dataBlockLowerCase == "smallductfan") shape = new SmallDuctFan(); + else if (dataBlockLowerCase == "magnet") + shape = new Magnet(); else if (dataBlockLowerCase == "antigravityitem") shape = new AntiGravity(cast element); else if (dataBlockLowerCase == "landmine") shape = new LandMine(); + else if (dataBlockLowerCase == "nuke") + shape = new Nuke(); else if (dataBlockLowerCase == "shockabsorberitem") shape = new ShockAbsorber(cast element); else if (dataBlockLowerCase == "superspeeditem") diff --git a/src/shapes/AntiGravity.hx b/src/shapes/AntiGravity.hx index c7ce72cf..7523183b 100644 --- a/src/shapes/AntiGravity.hx +++ b/src/shapes/AntiGravity.hx @@ -14,7 +14,7 @@ class AntiGravity extends PowerUp { this.isCollideable = false; this.isTSStatic = false; this.identifier = "AntiGravity"; - this.pickUpName = "Gravity Modifier"; + this.pickUpName = "Gravity Defier"; this.autoUse = true; } diff --git a/src/shapes/Helicopter.hx b/src/shapes/Helicopter.hx index 77601e8a..e0cd4d28 100644 --- a/src/shapes/Helicopter.hx +++ b/src/shapes/Helicopter.hx @@ -15,7 +15,7 @@ class Helicopter extends PowerUp { this.isTSStatic = false; this.showSequences = false; this.identifier = "Helicopter"; - this.pickUpName = "Gyrocopter PowerUp"; + this.pickUpName = "Helicopter PowerUp"; } public override function init(level:MarbleWorld, onFinish:Void->Void) { diff --git a/src/shapes/Magnet.hx b/src/shapes/Magnet.hx new file mode 100644 index 00000000..8500bf73 --- /dev/null +++ b/src/shapes/Magnet.hx @@ -0,0 +1,47 @@ +package shapes; + +import hxd.snd.effect.Spatialization; +import src.ResourceLoader; +import src.AudioManager; +import hxd.snd.Channel; +import h3d.Vector; +import src.ForceObject; + +class Magnet extends ForceObject { + var soundChannel:Channel; + + public function new() { + super(); + this.dtsPath = "data/shapes/hazards/magnet/magnet.dts"; + this.isCollideable = true; + this.isTSStatic = false; + this.identifier = "Magnet"; + this.forceDatas = [ + { + forceType: ForceCone, + forceNode: 0, + forceStrength: -90, + forceRadius: 10, + forceArc: 0.7, + forceVector: new Vector() + } + ]; + } + + public override function init(level:src.MarbleWorld, onFinish:Void->Void) { + super.init(level, () -> { + ResourceLoader.load("sound/magnet.wav").entry.load(() -> { + this.soundChannel = AudioManager.playSound(ResourceLoader.getResource("data/sound/magnet.wav", ResourceLoader.getAudio, this.soundResources), + new Vector(1e8, 1e8, 1e8), true); + onFinish(); + }); + }); + } + + public override function update(timeState:src.TimeState) { + super.update(timeState); + + var seffect = this.soundChannel.getEffect(Spatialization); + seffect.position = this.getAbsPos().getPosition(); + } +} diff --git a/src/shapes/Nuke.hx b/src/shapes/Nuke.hx new file mode 100644 index 00000000..14a963bd --- /dev/null +++ b/src/shapes/Nuke.hx @@ -0,0 +1,178 @@ +package shapes; + +import src.AudioManager; +import src.TimeState; +import collision.CollisionHull; +import collision.CollisionInfo; +import src.DtsObject; +import src.Util; +import src.ParticleSystem.ParticleEmitterOptions; +import src.ParticleSystem.ParticleData; +import h3d.Vector; +import src.ResourceLoader; +import src.MarbleWorld; + +final nukeParticle:ParticleEmitterOptions = { + ejectionPeriod: 0.2, + ambientVelocity: new Vector(0, 0, 0), + ejectionVelocity: 2, + velocityVariance: 1, + emitterLifetime: 50, + inheritedVelFactor: 0.2, + particleOptions: { + texture: 'particles/smoke.png', + blending: Add, + spinSpeed: 40, + spinRandomMin: -90, + spinRandomMax: 90, + lifetime: 1000, + lifetimeVariance: 150, + dragCoefficient: 0.8, + acceleration: 0, + colors: [new Vector(0.56, 0.36, 0.26, 1), new Vector(0.56, 0.36, 0.26, 0)], + sizes: [0.5, 1], + times: [0, 1] + } +}; + +final nukeSmokeParticle:ParticleEmitterOptions = { + ejectionPeriod: 0.5, + ambientVelocity: new Vector(0, 0, 0), + ejectionVelocity: 1.3, + velocityVariance: 0.5, + emitterLifetime: 50, + inheritedVelFactor: 0.25, + particleOptions: { + texture: 'particles/smoke.png', + blending: Alpha, + spinSpeed: 40, + spinRandomMin: -90, + spinRandomMax: 90, + lifetime: 2500, + lifetimeVariance: 300, + dragCoefficient: 0.7, + acceleration: -8, + colors: [ + new Vector(0.56, 0.36, 0.26, 1), + new Vector(0.2, 0.2, 0.2, 1), + new Vector(0, 0, 0, 0) + ], + sizes: [1, 1.5, 2], + times: [0, 0.5, 1] + } +}; + +final nukeSparksParticle:ParticleEmitterOptions = { + ejectionPeriod: 1.7, + ambientVelocity: new Vector(0, -0.5, 0), + ejectionVelocity: 13 / 1.5, + velocityVariance: 5, + emitterLifetime: 5000, + inheritedVelFactor: 0.2, + particleOptions: { + texture: 'particles/spark.png', + blending: Add, + spinSpeed: 40, + spinRandomMin: -90, + spinRandomMax: 90, + lifetime: 4500, + lifetimeVariance: 2500, + dragCoefficient: 0.5, + acceleration: 0, + colors: [ + new Vector(0.6, 0.4, 0.3, 1), + new Vector(0.6, 0.4, 0.3, 1), + new Vector(1, 0.4, 0.3, 0) + ], + sizes: [0.5, 0.4, 0.2], + times: [0, 0.5, 1] + } +}; + +class Nuke extends DtsObject { + var disappearTime = -1e8; + + var nukeParticleData:ParticleData; + var nukeSmokeParticleData:ParticleData; + var nukeSparkParticleData:ParticleData; + + public function new() { + super(); + dtsPath = "data/shapes/hazards/nuke/nuke.dts"; + this.identifier = "Nuke"; + this.isCollideable = true; + + nukeParticleData = new ParticleData(); + nukeParticleData.identifier = "nukeParticle"; + nukeParticleData.texture = ResourceLoader.getResource("data/particles/smoke.png", ResourceLoader.getTexture, this.textureResources); + + nukeSmokeParticleData = new ParticleData(); + nukeSmokeParticleData.identifier = "nukeSmokeParticle"; + nukeSmokeParticleData.texture = ResourceLoader.getResource("data/particles/smoke.png", ResourceLoader.getTexture, this.textureResources); + + nukeSparkParticleData = new ParticleData(); + nukeSparkParticleData.identifier = "nukeSparkParticle"; + nukeSparkParticleData.texture = ResourceLoader.getResource("data/particles/spark.png", ResourceLoader.getTexture, this.textureResources); + } + + public override function init(level:MarbleWorld, onFinish:Void->Void) { + super.init(level, () -> { + ResourceLoader.load("sound/nukeexplode.wav").entry.load(onFinish); + }); + } + + override function onMarbleContact(timeState:TimeState, ?contact:CollisionInfo) { + if (this.isCollideable) { + // marble.velocity = marble.velocity.add(vec); + this.disappearTime = timeState.timeSinceLoad; + this.setCollisionEnabled(false); + + // if (!this.level.rewinding) + AudioManager.playSound(ResourceLoader.getResource("data/sound/nukeexplode.wav", ResourceLoader.getAudio, this.soundResources)); + this.level.particleManager.createEmitter(nukeParticle, nukeParticleData, this.getAbsPos().getPosition()); + this.level.particleManager.createEmitter(nukeSmokeParticle, nukeSmokeParticleData, this.getAbsPos().getPosition()); + this.level.particleManager.createEmitter(nukeSparksParticle, nukeSparkParticleData, this.getAbsPos().getPosition()); + + var marble = this.level.marble; + var minePos = this.getAbsPos().getPosition(); + var off = marble.getAbsPos().getPosition().sub(minePos); + + var force = computeExplosionForce(off); + + marble.applyImpulse(force); + + // for (collider in this.colliders) { + // var hull:CollisionHull = cast collider; + // hull.force = strength; + // } + } + // Normally, we would add a light here, but that's too expensive for THREE, apparently. + + // this.level.replay.recordMarbleContact(this); + } + + function computeExplosionForce(distVec:Vector) { + var range = 10; + var power = 100; + + var dist = distVec.length(); + if (dist < range) { + var scalar = (1 - dist / range) * power; + distVec = distVec.multiply(scalar); + } + + return distVec; + } + + override function update(timeState:TimeState) { + super.update(timeState); + if (timeState.timeSinceLoad >= this.disappearTime + 15 || timeState.timeSinceLoad < this.disappearTime) { + this.setHide(false); + } else { + this.setHide(true); + } + + var opacity = Util.clamp((timeState.timeSinceLoad - (this.disappearTime + 15)), 0, 1); + this.setOpacity(opacity); + } +} diff --git a/src/shapes/ShockAbsorber.hx b/src/shapes/ShockAbsorber.hx index decf4514..71a104c0 100644 --- a/src/shapes/ShockAbsorber.hx +++ b/src/shapes/ShockAbsorber.hx @@ -13,7 +13,7 @@ class ShockAbsorber extends PowerUp { this.isCollideable = false; this.isTSStatic = false; this.identifier = "ShockAbsorber"; - this.pickUpName = "Shock Absorber PowerUp"; + this.pickUpName = "Anti-Recoil PowerUp"; } public override function init(level:MarbleWorld, onFinish:Void->Void) { diff --git a/src/shapes/SuperBounce.hx b/src/shapes/SuperBounce.hx index 233f32cc..a8a1ed04 100644 --- a/src/shapes/SuperBounce.hx +++ b/src/shapes/SuperBounce.hx @@ -13,7 +13,7 @@ class SuperBounce extends PowerUp { this.isCollideable = false; this.isTSStatic = false; this.identifier = "SuperBounce"; - this.pickUpName = "Super Bounce PowerUp"; + this.pickUpName = "Marble Recoil PowerUp"; } public function pickUp():Bool { diff --git a/src/shapes/SuperJump.hx b/src/shapes/SuperJump.hx index 012b4bd4..35cffb89 100644 --- a/src/shapes/SuperJump.hx +++ b/src/shapes/SuperJump.hx @@ -42,7 +42,7 @@ class SuperJump extends PowerUp { this.isCollideable = false; this.isTSStatic = false; this.identifier = "SuperJump"; - this.pickUpName = "Super Jump PowerUp"; + this.pickUpName = "Jump Boost PowerUp"; sjEmitterParticleData = new ParticleData(); sjEmitterParticleData.identifier = "superJumpParticle"; sjEmitterParticleData.texture = ResourceLoader.getResource("data/particles/twirl.png", ResourceLoader.getTexture, this.textureResources); diff --git a/src/shapes/SuperSpeed.hx b/src/shapes/SuperSpeed.hx index df7528f0..71d2c2c5 100644 --- a/src/shapes/SuperSpeed.hx +++ b/src/shapes/SuperSpeed.hx @@ -47,7 +47,7 @@ class SuperSpeed extends PowerUp { this.isCollideable = false; this.isTSStatic = false; this.identifier = "SuperSpeed"; - this.pickUpName = "Super Speed PowerUp"; + this.pickUpName = "Speed Booster PowerUp"; this.useInstancing = true; ssEmitterParticleData = new ParticleData(); ssEmitterParticleData.identifier = "superSpeedParticle"; diff --git a/src/shapes/TimeTravel.hx b/src/shapes/TimeTravel.hx index 2cef364b..e4b90584 100644 --- a/src/shapes/TimeTravel.hx +++ b/src/shapes/TimeTravel.hx @@ -20,7 +20,7 @@ class TimeTravel extends PowerUp { this.timeBonus = MisParser.parseNumber(element.timebonus) / 1000; } - this.pickUpName = '${this.timeBonus} second Time Travel bonus'; + this.pickUpName = '${this.timeBonus} second Time ${this.timeBonus >= 0 ? 'Modifier' : 'Penalty'}'; this.cooldownDuration = 1e8; this.useInstancing = true; this.autoUse = true;