Skip to content

Commit bcee289

Browse files
authored
Merge pull request #11 from SilverDorian46/dev
Reskinnable Throw Boxes + "can pass through Spinners" option
2 parents d2b73e1 + 0883a96 commit bcee289

File tree

8 files changed

+280
-30
lines changed

8 files changed

+280
-30
lines changed

Code/Entities/ThrowBox.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public class ThrowBox : Actor {
3939
private readonly string _levelName;
4040
private readonly bool _tutorial;
4141
private readonly TransitionListener _transitionListener;
42+
private readonly bool _canPassThroughSpinners;
43+
private readonly ParticleType _p_Impact;
44+
private readonly char _debrisTypeOverride;
4245

4346
private Vector2 _prevLiftSpeed;
4447
private Level _level;
@@ -55,7 +58,8 @@ public class ThrowBox : Actor {
5558
private BirdTutorialGui _tutorialPutDown;
5659
private bool _isCrucial;
5760

58-
public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSpecial = false, bool isCrucial = false)
61+
public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSpecial = false, bool isCrucial = false, bool canPassThroughSpinners = false,
62+
string crateTextureOverride = null, string crucialTextureOverride = null, ParticleType impactParticlesOverride = null, char debrisTypeOverride = '\0')
5963
: base(position) {
6064
Position -= DISPLACEMENT;
6165
_starterPosition = Position;
@@ -65,13 +69,21 @@ public ThrowBox(Vector2 position, bool isMetal, bool tutorial = false, bool isSp
6569
IsSpecial = isSpecial;
6670
_isCrucial = isCrucial;
6771
_tutorial = tutorial;
68-
string pathString = isMetal ? "crate_metal0" : "crate0";
72+
_canPassThroughSpinners = canPassThroughSpinners;
6973

70-
Add(_image = new Image(GFX.Game[$"objects/FactoryHelper/crate/{pathString}"]));
74+
string crateTexture;
75+
if (string.IsNullOrEmpty(crateTextureOverride)) {
76+
string pathString = isMetal ? "crate_metal0" : "crate0";
77+
crateTexture = $"objects/FactoryHelper/crate/{pathString}";
78+
} else {
79+
crateTexture = crateTextureOverride;
80+
}
81+
Add(_image = new Image(GFX.Game[crateTexture]));
7182
_image.Position += DISPLACEMENT;
7283

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

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

99111
Add(new LightOcclude(0.2f));
100112
Add(new MirrorReflection());
113+
114+
_p_Impact = impactParticlesOverride ?? P_Impact;
115+
_debrisTypeOverride = debrisTypeOverride;
101116
}
102117

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

124+
private static string GetCrateTextureOverride(EntityData data) {
125+
return data.Bool("overrideTextures", false) ? data.Attr("crateTexturePath") : null;
126+
}
127+
128+
private static string GetCrucialTextureOverride(EntityData data) {
129+
return data.Bool("overrideTextures", false) ? data.Attr("crucialTexturePath") : null;
130+
}
131+
132+
private static ParticleType GetImpactParticlesOverride(EntityData data) {
133+
return data.Bool("overrideParticles", false) ? new ParticleType(P_Impact) {
134+
Color = data.HexColor("impactParticlesColor")
135+
} : null;
136+
}
137+
138+
private static char GetDebrisTypeOverride(EntityData data) {
139+
return data.Bool("overrideDebris", false) ? data.Char("debrisFromTiletype") : '\0';
140+
}
141+
108142
private void OnSteamWall(SteamWall steamWall) {
109143
Shatter();
110144
}
111145

112146
private void OnHitSpinner(Entity spinner) {
113-
Shatter();
147+
if (!_canPassThroughSpinners)
148+
Shatter();
114149
}
115150

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

422-
(Scene as Level).Particles.Emit(P_Impact, 12, position, positionRange, direction);
457+
(Scene as Level).Particles.Emit(_p_Impact, 12, position, positionRange, direction);
423458
}
424459

425460
private void Shatter() {
@@ -434,7 +469,9 @@ private void Shatter() {
434469

435470
for (int i = 0; i < Width / 8f; i++) {
436471
for (int j = 0; j < Height / 8f; j++) {
437-
if (_isMetal) {
472+
if (_debrisTypeOverride != '\0') {
473+
Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, _debrisTypeOverride, false).BlastFrom(Center));
474+
} else if (_isMetal) {
438475
Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, '8', false).BlastFrom(Center));
439476
} else {
440477
Scene.Add(Engine.Pooler.Create<Debris>().Init(Position + new Vector2(4 + (i * 8), 4 + (j * 8)) + DISPLACEMENT, '9', false).BlastFrom(Center));

Code/Entities/ThrowBoxSpawner.cs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@ public class ThrowBoxSpawner : Entity {
1919
private readonly HashSet<ThrowBox> _boxes = new();
2020
private readonly bool _fromTop;
2121
private readonly bool _tutorial;
22+
private readonly bool _canPassThroughSpinners;
2223

23-
public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activationId, bool isMetal, bool isRandom, bool fromTop, bool tutorial, bool startActive) : base(position) {
24+
private readonly string _woodenCrateTextureOverride;
25+
private readonly string _metalCrateTextureOverride;
26+
private readonly ParticleType _impactParticlesOverride;
27+
private readonly char _woodenDebrisTypeOverride;
28+
private readonly char _metalDebrisTypeOverride;
29+
30+
public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activationId, bool isMetal, bool isRandom, bool fromTop, bool tutorial, bool startActive, bool canPassThroughSpinners = false,
31+
string woodenCrateTextureOverride = null, string metalCrateTextureOverride = null, ParticleType impactParticlesOverride = null, char woodenDebrisTypeOverride = '\0', char metalDebrisTypeOverride = '\0')
32+
: base(position) {
2433
Add(Activator = new FactoryActivator());
2534
Activator.ActivationId = activationId == string.Empty ? null : activationId;
2635
Activator.StartOn = startActive;
@@ -33,13 +42,44 @@ public ThrowBoxSpawner(Vector2 position, float delay, int maximum, string activa
3342
_isRandom = isRandom;
3443
_fromTop = fromTop;
3544
_tutorial = tutorial;
45+
_canPassThroughSpinners = canPassThroughSpinners;
46+
47+
_woodenCrateTextureOverride = woodenCrateTextureOverride;
48+
_metalCrateTextureOverride = metalCrateTextureOverride;
49+
_impactParticlesOverride = impactParticlesOverride;
50+
_woodenDebrisTypeOverride = woodenDebrisTypeOverride;
51+
_metalDebrisTypeOverride = metalDebrisTypeOverride;
52+
3653
Add(new Coroutine(SpawnSequence()));
3754
Add(new SteamCollider(OnSteamWall));
3855
}
3956

4057
public ThrowBoxSpawner(EntityData data, Vector2 offset)
4158
: this(data.Position + offset, data.Float("delay", 5f), data.Int("maximum", 0), data.Attr("activationId"), data.Bool("isMetal", false),
42-
data.Bool("isRandom", false), data.Bool("fromTop", true), data.Bool("tutorial", false), data.Bool("startActive", true)) {
59+
data.Bool("isRandom", false), data.Bool("fromTop", true), data.Bool("tutorial", false), data.Bool("startActive", true), data.Bool("canPassThroughSpinners", false),
60+
GetWoodenCrateTextureOverride(data), GetMetalCrateTextureOverride(data), GetImpactParticlesOverride(data), GetWoodenDebrisTypeOverride(data), GetMetalDebrisTypeOverride(data)) {
61+
}
62+
63+
private static string GetWoodenCrateTextureOverride(EntityData data) {
64+
return data.Bool("overrideTextures", false) ? data.Attr("woodenCrateTexturePath") : null;
65+
}
66+
67+
private static string GetMetalCrateTextureOverride(EntityData data) {
68+
return data.Bool("overrideTextures", false) ? data.Attr("metalCrateTexturePath") : null;
69+
}
70+
71+
private static ParticleType GetImpactParticlesOverride(EntityData data) {
72+
return data.Bool("overrideParticles", false) ? new ParticleType(ThrowBox.P_Impact) {
73+
Color = data.HexColor("impactParticlesColor")
74+
} : null;
75+
}
76+
77+
private static char GetWoodenDebrisTypeOverride(EntityData data) {
78+
return data.Bool("overrideDebris", false) ? data.Char("woodenDebrisFromTiletype") : '\0';
79+
}
80+
81+
private static char GetMetalDebrisTypeOverride(EntityData data) {
82+
return data.Bool("overrideDebris", false) ? data.Char("metalDebrisFromTiletype") : '\0';
4383
}
4484

4585
private void OnSteamWall(SteamWall steamWall) {
@@ -66,10 +106,24 @@ private void TrySpawnThrowBox() {
66106
if (_maximum <= 0 || _boxes.Count < _maximum) {
67107
float posY = _fromTop ? SceneAs<Level>().Bounds.Top - 15 : Position.Y;
68108
float posX = _fromTop ? Position.X : GetClosestPositionH();
109+
bool isMetal = _isRandom ? Calc.Random.Chance(0.5f) : _isMetal;
110+
string crateTextureOverride;
111+
char debrisTypeOverride;
112+
if (isMetal) {
113+
crateTextureOverride = _metalCrateTextureOverride;
114+
debrisTypeOverride = _metalDebrisTypeOverride;
115+
} else {
116+
crateTextureOverride = _woodenCrateTextureOverride;
117+
debrisTypeOverride = _woodenDebrisTypeOverride;
118+
}
69119
ThrowBox crate = new(
70120
position: new Vector2(posX, posY),
71-
isMetal: _isRandom ? Calc.Random.Chance(0.5f) : _isMetal,
72-
tutorial: _tutorial
121+
isMetal: isMetal,
122+
tutorial: _tutorial,
123+
canPassThroughSpinners: _canPassThroughSpinners,
124+
crateTextureOverride: crateTextureOverride,
125+
impactParticlesOverride: _impactParticlesOverride,
126+
debrisTypeOverride: debrisTypeOverride
73127
);
74128
Scene.Add(crate);
75129
_boxes.Add(crate);

Code/FactoryHelperHooks.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ public static void Load() {
2020
On.Celeste.DashBlock.RemoveAndFlagAsGone += DashBlockRemoveAndFlagAsGone;
2121
}
2222

23+
public static void Unload() {
24+
On.Celeste.Player.ctor -= ctor;
25+
On.Celeste.Level.LoadLevel -= LoadLevel;
26+
On.Celeste.Player.Die -= PlayerDie;
27+
On.Celeste.LevelExit.Routine -= RespawnRoutine;
28+
On.Celeste.Player.Pickup -= Pickup;
29+
On.Celeste.Lookout.LookRoutine -= LookRoutine;
30+
On.Celeste.LevelEnter.Go -= LevelEnterGo;
31+
On.Celeste.DashBlock.Break_Vector2_Vector2_bool_bool -= DashBlockBreak;
32+
On.Celeste.DashBlock.RemoveAndFlagAsGone -= DashBlockRemoveAndFlagAsGone;
33+
}
34+
2335
private static void DashBlockRemoveAndFlagAsGone(On.Celeste.DashBlock.orig_RemoveAndFlagAsGone orig, DashBlock self) {
2436
if (self is FactoryActivatorDashBlock) {
2537
self.RemoveSelf();

Code/FactoryHelperModule.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public override void Load() {
2828
FactoryHelperHooks.Load();
2929
}
3030

31-
public override void Unload() { }
31+
public override void Unload() {
32+
FactoryHelperHooks.Unload();
33+
}
3234
}
3335
}

Loenn/entities/crate.lua

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1+
local drawableSprite = require("structs.drawable_sprite")
2+
local fakeTilesHelper = require("helpers.fake_tiles")
3+
14
local crate = {}
25

36
crate.name = "FactoryHelper/ThrowBox"
47

8+
crate.fieldInformation = function()
9+
return {
10+
impactParticlesColor = {
11+
fieldType = "color"
12+
},
13+
debrisFromTiletype = {
14+
options = fakeTilesHelper.getTilesOptions(),
15+
editable = false
16+
}
17+
}
18+
end
19+
520
crate.placements = {
621
{
722
name = "wood",
823
data = {
924
isMetal = false,
1025
tutorial = false,
1126
isSpecial = false,
12-
isCrucial = false
27+
isCrucial = false,
28+
canPassThroughSpinners = false
1329
}
1430
},
1531
{
@@ -18,15 +34,74 @@ crate.placements = {
1834
isMetal = true,
1935
tutorial = false,
2036
isSpecial = false,
21-
isCrucial = false
37+
isCrucial = false,
38+
canPassThroughSpinners = false
39+
}
40+
},
41+
{
42+
name = "reskin_wood",
43+
data = {
44+
isMetal = false,
45+
tutorial = false,
46+
isSpecial = false,
47+
isCrucial = false,
48+
canPassThroughSpinners = false,
49+
overrideTextures = true,
50+
crateTexturePath = "objects/FactoryHelper/crate/crate0",
51+
crucialTexturePath = "objects/FactoryHelper/crate/crucial",
52+
overrideParticles = false,
53+
impactParticlesColor = "9c8d7b",
54+
overrideDebris = false,
55+
debrisFromTiletype = '9'
56+
}
57+
},
58+
{
59+
name = "reskin_metal",
60+
data = {
61+
isMetal = true,
62+
tutorial = false,
63+
isSpecial = false,
64+
isCrucial = false,
65+
canPassThroughSpinners = false,
66+
overrideTextures = true,
67+
crateTexturePath = "objects/FactoryHelper/crate/crate_metal0",
68+
crucialTexturePath = "objects/FactoryHelper/crate/crucial",
69+
overrideParticles = false,
70+
impactParticlesColor = "9c8d7b",
71+
overrideDebris = false,
72+
debrisFromTiletype = '8'
2273
}
2374
}
2475
}
2576

26-
function crate.texture(sprite, entity)
27-
return entity.isMetal and "objects/FactoryHelper/crate/crate_metal0" or "objects/FactoryHelper/crate/crate0"
28-
end
77+
local justification = {0.0, 0.0}
78+
79+
function crate.sprite(room, entity)
80+
local sprites = {}
81+
82+
if (entity.overrideTextures) then
83+
local crateSprite = drawableSprite.fromTexture(entity.crateTexturePath or "", entity)
84+
crateSprite:setJustification(justification)
85+
table.insert(sprites, crateSprite)
2986

30-
crate.justification = {0.0, 0.0}
87+
if (entity.isCrucial) then
88+
local crucialSprite = drawableSprite.fromTexture(entity.crucialTexturePath or "", entity)
89+
crucialSprite:setJustification(justification)
90+
table.insert(sprites, crucialSprite)
91+
end
92+
else
93+
local crateSprite = drawableSprite.fromTexture(entity.isMetal and "objects/FactoryHelper/crate/crate_metal0" or "objects/FactoryHelper/crate/crate0", entity)
94+
crateSprite:setJustification(justification)
95+
table.insert(sprites, crateSprite)
96+
97+
if (entity.isCrucial) then
98+
local crucialSprite = drawableSprite.fromTexture("objects/FactoryHelper/crate/crucial", entity)
99+
crucialSprite:setJustification(justification)
100+
table.insert(sprites, crucialSprite)
101+
end
102+
end
103+
104+
return sprites
105+
end
31106

32107
return crate

0 commit comments

Comments
 (0)