Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 45 additions & 8 deletions Code/Entities/ThrowBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class ThrowBox : Actor {
private readonly string _levelName;
private readonly bool _tutorial;
private readonly TransitionListener _transitionListener;
private readonly bool _canPassThroughSpinners;
private readonly ParticleType _p_Impact;
private readonly char _debrisTypeOverride;

private Vector2 _prevLiftSpeed;
private Level _level;
Expand All @@ -55,7 +58,8 @@ public class ThrowBox : Actor {
private BirdTutorialGui _tutorialPutDown;
private bool _isCrucial;

public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSpecial = false, bool isCrucial = false)
public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSpecial = false, bool isCrucial = false, bool canPassThroughSpinners = false,
string crateTextureOverride = null, string crucialTextureOverride = null, ParticleType impactParticlesOverride = null, char debrisTypeOverride = '\0')
: base(position) {
Position -= DISPLACEMENT;
_starterPosition = Position;
Expand All @@ -65,13 +69,21 @@ public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSp
IsSpecial = isSpecial;
_isCrucial = isCrucial;
_tutorial = tutorial;
string pathString = isMetal ? "crate_metal0" : "crate0";
_canPassThroughSpinners = canPassThroughSpinners;

Add(_image = new Image(GFX.Game[$"objects/FactoryHelper/crate/{pathString}"]));
string crateTexture;
if (string.IsNullOrEmpty(crateTextureOverride)) {
string pathString = isMetal ? "crate_metal0" : "crate0";
crateTexture = $"objects/FactoryHelper/crate/{pathString}";
} else {
crateTexture = crateTextureOverride;
}
Add(_image = new Image(GFX.Game[crateTexture]));
_image.Position += DISPLACEMENT;

if (_isCrucial) {
Add(_warningImage = new Image(GFX.Game["objects/FactoryHelper/crate/crucial"]));
string crucialTexture = string.IsNullOrEmpty(crucialTextureOverride) ? "objects/FactoryHelper/crate/crucial" : crucialTextureOverride;
Add(_warningImage = new Image(GFX.Game[crucialTexture]));
_warningImage.Position += DISPLACEMENT;
}

Expand All @@ -98,19 +110,42 @@ public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSp

Add(new LightOcclude(0.2f));
Add(new MirrorReflection());

_p_Impact = impactParticlesOverride ?? P_Impact;
_debrisTypeOverride = debrisTypeOverride;
}

public ThrowBox(EntityData data, Vector2 offset)
: this(data.Position + offset, data.Bool("isMetal", false), data.Bool("tutorial", false), data.Bool("isSpecial", false), data.Bool("isCrucial", false)) {
: this(data.Position + offset, data.Bool("isMetal", false), data.Bool("tutorial", false), data.Bool("isSpecial", false), data.Bool("isCrucial", false), data.Bool("canPassThroughSpinners", false),
GetCrateTextureOverride(data), GetCrucialTextureOverride(data), GetImpactParticlesOverride(data), GetDebrisTypeOverride(data)) {
_levelName = data.Level.Name;
}

private static string GetCrateTextureOverride(EntityData data) {
return data.Bool("overrideTextures", false) ? data.Attr("crateTexturePath") : null;
}

private static string GetCrucialTextureOverride(EntityData data) {
return data.Bool("overrideTextures", false) ? data.Attr("crucialTexturePath") : null;
}

private static ParticleType GetImpactParticlesOverride(EntityData data) {
return data.Bool("overrideParticles", false) ? new ParticleType(P_Impact) {
Color = data.HexColor("impactParticlesColor")
} : null;
}

private static char GetDebrisTypeOverride(EntityData data) {
return data.Bool("overrideDebris", false) ? data.Char("debrisFromTiletype") : '\0';
}

private void OnSteamWall(SteamWall steamWall) {
Shatter();
}

private void OnHitSpinner(Entity spinner) {
Shatter();
if (!_canPassThroughSpinners)
Shatter();
}

public override void Added(Scene scene) {
Expand Down Expand Up @@ -419,7 +454,7 @@ private void ImpactParticles(Vector2 dir) {
positionRange = Vector2.UnitX * 6f;
}

(Scene as Level).Particles.Emit(P_Impact, 12, position, positionRange, direction);
(Scene as Level).Particles.Emit(_p_Impact, 12, position, positionRange, direction);
}

private void Shatter() {
Expand All @@ -434,7 +469,9 @@ private void Shatter() {

for (int i = 0; i < Width / 8f; i++) {
for (int j = 0; j < Height / 8f; j++) {
if (_isMetal) {
if (_debrisTypeOverride != '\0') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would make more sense to use a nullable char rather than checking for a magic \0

Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, _debrisTypeOverride, false).BlastFrom(Center));
} else if (_isMetal) {
Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, '8', false).BlastFrom(Center));
} else {
Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, '9', false).BlastFrom(Center));
Expand Down
62 changes: 58 additions & 4 deletions Code/Entities/ThrowBoxSpawner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,17 @@ public class ThrowBoxSpawner : Entity {
private readonly HashSet<ThrowBox> _boxes = new();
private readonly bool _fromTop;
private readonly bool _tutorial;
private readonly bool _canPassThroughSpinners;

public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activationId, bool isMetal, bool isRandom, bool fromTop, bool tutorial, bool startActive) : base(position) {
private readonly string _woodenCrateTextureOverride;
private readonly string _metalCrateTextureOverride;
private readonly ParticleType _impactParticlesOverride;
private readonly char _woodenDebrisTypeOverride;
private readonly char _metalDebrisTypeOverride;

public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activationId, bool isMetal, bool isRandom, bool fromTop, bool tutorial, bool startActive, bool canPassThroughSpinners = false,
string woodenCrateTextureOverride = null, string metalCrateTextureOverride = null, ParticleType impactParticlesOverride = null, char woodenDebrisTypeOverride = '\0', char metalDebrisTypeOverride = '\0')
: base(position) {
Add(Activator = new FactoryActivator());
Activator.ActivationId = activationId == string.Empty ? null : activationId;
Activator.StartOn = startActive;
Expand All @@ -33,13 +42,44 @@ public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activa
_isRandom = isRandom;
_fromTop = fromTop;
_tutorial = tutorial;
_canPassThroughSpinners = canPassThroughSpinners;

_woodenCrateTextureOverride = woodenCrateTextureOverride;
_metalCrateTextureOverride = metalCrateTextureOverride;
_impactParticlesOverride = impactParticlesOverride;
_woodenDebrisTypeOverride = woodenDebrisTypeOverride;
_metalDebrisTypeOverride = metalDebrisTypeOverride;

Add(new Coroutine(SpawnSequence()));
Add(new SteamCollider(OnSteamWall));
}

public ThrowBoxSpawner(EntityData data, Vector2 offset)
: this(data.Position + offset, data.Float("delay", 5f), data.Int("maximum", 0), data.Attr("activationId"), data.Bool("isMetal", false),
data.Bool("isRandom", false), data.Bool("fromTop", true), data.Bool("tutorial", false), data.Bool("startActive", true)) {
data.Bool("isRandom", false), data.Bool("fromTop", true), data.Bool("tutorial", false), data.Bool("startActive", true), data.Bool("canPassThroughSpinners", false),
GetWoodenCrateTextureOverride(data), GetMetalCrateTextureOverride(data), GetImpactParticlesOverride(data), GetWoodenDebrisTypeOverride(data), GetMetalDebrisTypeOverride(data)) {
}

private static string GetWoodenCrateTextureOverride(EntityData data) {
return data.Bool("overrideTextures", false) ? data.Attr("woodenCrateTexturePath") : null;
}

private static string GetMetalCrateTextureOverride(EntityData data) {
return data.Bool("overrideTextures", false) ? data.Attr("metalCrateTexturePath") : null;
}

private static ParticleType GetImpactParticlesOverride(EntityData data) {
return data.Bool("overrideParticles", false) ? new ParticleType(ThrowBox.P_Impact) {
Color = data.HexColor("impactParticlesColor")
} : null;
}

private static char GetWoodenDebrisTypeOverride(EntityData data) {
return data.Bool("overrideDebris", false) ? data.Char("woodenDebrisFromTiletype") : '\0';
}

private static char GetMetalDebrisTypeOverride(EntityData data) {
return data.Bool("overrideDebris", false) ? data.Char("metalDebrisFromTiletype") : '\0';
}

private void OnSteamWall(SteamWall steamWall) {
Expand All @@ -66,10 +106,24 @@ private void TrySpawnThrowBox() {
if (_maximum <= 0 || _boxes.Count < _maximum) {
float posY = _fromTop ? SceneAs<Level>().Bounds.Top - 15 : Position.Y;
float posX = _fromTop ? Position.X : GetClosestPositionH();
bool isMetal = _isRandom ? Calc.Random.Chance(0.5f) : _isMetal;
string crateTextureOverride;
char debrisTypeOverride;
if (isMetal) {
crateTextureOverride = _metalCrateTextureOverride;
debrisTypeOverride = _metalDebrisTypeOverride;
} else {
crateTextureOverride = _woodenCrateTextureOverride;
debrisTypeOverride = _woodenDebrisTypeOverride;
}
ThrowBox crate = new(
position: new Vector2(posX, posY),
isMetal: _isRandom ? Calc.Random.Chance(0.5f) : _isMetal,
tutorial: _tutorial
isMetal: isMetal,
tutorial: _tutorial,
canPassThroughSpinners: _canPassThroughSpinners,
crateTextureOverride: crateTextureOverride,
impactParticlesOverride: _impactParticlesOverride,
debrisTypeOverride: debrisTypeOverride
);
Scene.Add(crate);
_boxes.Add(crate);
Expand Down
12 changes: 12 additions & 0 deletions Code/FactoryHelperHooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ public static void Load() {
On.Celeste.DashBlock.RemoveAndFlagAsGone += DashBlockRemoveAndFlagAsGone;
}

public static void Unload() {
On.Celeste.Player.ctor -= ctor;
On.Celeste.Level.LoadLevel -= LoadLevel;
On.Celeste.Player.Die -= PlayerDie;
On.Celeste.LevelExit.Routine -= RespawnRoutine;
On.Celeste.Player.Pickup -= Pickup;
On.Celeste.Lookout.LookRoutine -= LookRoutine;
On.Celeste.LevelEnter.Go -= LevelEnterGo;
On.Celeste.DashBlock.Break_Vector2_Vector2_bool_bool -= DashBlockBreak;
On.Celeste.DashBlock.RemoveAndFlagAsGone -= DashBlockRemoveAndFlagAsGone;
}
Comment on lines +23 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whaaaaaaaaaaaaaa
THANK YOU for this


private static void DashBlockRemoveAndFlagAsGone(On.Celeste.DashBlock.orig_RemoveAndFlagAsGone orig, DashBlock self) {
if (self is FactoryActivatorDashBlock) {
self.RemoveSelf();
Expand Down
4 changes: 3 additions & 1 deletion Code/FactoryHelperModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public override void Load() {
FactoryHelperHooks.Load();
}

public override void Unload() { }
public override void Unload() {
FactoryHelperHooks.Unload();
}
}
}
87 changes: 81 additions & 6 deletions Loenn/entities/crate.lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
local drawableSprite = require("structs.drawable_sprite")
local fakeTilesHelper = require("helpers.fake_tiles")

local crate = {}

crate.name = "FactoryHelper/ThrowBox"

crate.fieldInformation = function()
return {
impactParticlesColor = {
fieldType = "color"
},
debrisFromTiletype = {
options = fakeTilesHelper.getTilesOptions(),
editable = false
}
}
end

crate.placements = {
{
name = "wood",
data = {
isMetal = false,
tutorial = false,
isSpecial = false,
isCrucial = false
isCrucial = false,
canPassThroughSpinners = false
}
},
{
Expand All @@ -18,15 +34,74 @@ crate.placements = {
isMetal = true,
tutorial = false,
isSpecial = false,
isCrucial = false
isCrucial = false,
canPassThroughSpinners = false
}
},
{
name = "reskin_wood",
data = {
isMetal = false,
tutorial = false,
isSpecial = false,
isCrucial = false,
canPassThroughSpinners = false,
overrideTextures = true,
crateTexturePath = "objects/FactoryHelper/crate/crate0",
crucialTexturePath = "objects/FactoryHelper/crate/crucial",
overrideParticles = false,
impactParticlesColor = "9c8d7b",
overrideDebris = false,
debrisFromTiletype = '9'
}
},
{
name = "reskin_metal",
data = {
isMetal = true,
tutorial = false,
isSpecial = false,
isCrucial = false,
canPassThroughSpinners = false,
overrideTextures = true,
crateTexturePath = "objects/FactoryHelper/crate/crate_metal0",
crucialTexturePath = "objects/FactoryHelper/crate/crucial",
overrideParticles = false,
impactParticlesColor = "9c8d7b",
overrideDebris = false,
debrisFromTiletype = '8'
}
}
}

function crate.texture(sprite, entity)
return entity.isMetal and "objects/FactoryHelper/crate/crate_metal0" or "objects/FactoryHelper/crate/crate0"
end
local justification = {0.0, 0.0}

function crate.sprite(room, entity)
local sprites = {}

if (entity.overrideTextures) then
local crateSprite = drawableSprite.fromTexture(entity.crateTexturePath or "", entity)
crateSprite:setJustification(justification)
table.insert(sprites, crateSprite)

crate.justification = {0.0, 0.0}
if (entity.isCrucial) then
local crucialSprite = drawableSprite.fromTexture(entity.crucialTexturePath or "", entity)
crucialSprite:setJustification(justification)
table.insert(sprites, crucialSprite)
end
else
local crateSprite = drawableSprite.fromTexture(entity.isMetal and "objects/FactoryHelper/crate/crate_metal0" or "objects/FactoryHelper/crate/crate0", entity)
crateSprite:setJustification(justification)
table.insert(sprites, crateSprite)

if (entity.isCrucial) then
local crucialSprite = drawableSprite.fromTexture("objects/FactoryHelper/crate/crucial", entity)
crucialSprite:setJustification(justification)
table.insert(sprites, crucialSprite)
end
end

return sprites
end

return crate
Loading