diff --git a/data/images/creatures/crusher/corrupted/krosh_corrupt.sprite b/data/images/creatures/crusher/corrupted/krosh_corrupt.sprite index f1783a7fa25..de7c29d7375 100644 --- a/data/images/creatures/crusher/corrupted/krosh_corrupt.sprite +++ b/data/images/creatures/crusher/corrupted/krosh_corrupt.sprite @@ -18,18 +18,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 16 16 128 128) - (images "krosh_corrupt_whites.png") + (images "krosh_corrupt_eyes.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 16 16 128 128) (images "krosh_corrupt_eyes.png") ) (action - (name "righteye") + (name "whites") (hitbox 16 16 128 128) - (images "krosh_corrupt_eyes.png") + (images "krosh_corrupt_whites.png") + ) + + (linked-sprites + (left-eye "krosh_corrupt.sprite" "left-eye") + (right-eye "krosh_corrupt.sprite" "right-eye") + (whites "krosh_corrupt.sprite" "whites") ) ) diff --git a/data/images/creatures/crusher/corrupted/krush_corrupt.sprite b/data/images/creatures/crusher/corrupted/krush_corrupt.sprite index 7cd9c5a713e..ab1e729af85 100644 --- a/data/images/creatures/crusher/corrupted/krush_corrupt.sprite +++ b/data/images/creatures/crusher/corrupted/krush_corrupt.sprite @@ -18,18 +18,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 8 8 64 64) - (images "krush_corrupt_whites.png") + (images "krush_corrupt_eyes.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 8 8 64 64) (images "krush_corrupt_eyes.png") ) (action - (name "righteye") + (name "whites") (hitbox 8 8 64 64) - (images "krush_corrupt_eyes.png") + (images "krush_corrupt_whites.png") + ) + + (linked-sprites + (left-eye "krush_corrupt.sprite" "left-eye") + (right-eye "krush_corrupt.sprite" "right-eye") + (whites "krush_corrupt.sprite" "whites") ) ) diff --git a/data/images/creatures/crusher/krosh_ice.sprite b/data/images/creatures/crusher/krosh_ice.sprite index e013731a958..32454d42468 100644 --- a/data/images/creatures/crusher/krosh_ice.sprite +++ b/data/images/creatures/crusher/krosh_ice.sprite @@ -18,18 +18,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 4 4 128 128) - (images "krosh_ice_whites.png") + (images "krosh_ice_lefteye.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 4 4 128 128) - (images "krosh_ice_lefteye.png") + (images "krosh_ice_righteye.png") ) (action - (name "righteye") + (name "whites") (hitbox 4 4 128 128) - (images "krosh_ice_righteye.png") + (images "krosh_ice_whites.png") + ) + + (linked-sprites + (left-eye "krosh_ice.sprite" "left-eye") + (right-eye "krosh_ice.sprite" "right-eye") + (whites "krosh_ice.sprite" "whites") ) ) diff --git a/data/images/creatures/crusher/krosh_rock.sprite b/data/images/creatures/crusher/krosh_rock.sprite index e973843b109..ca847cc5248 100644 --- a/data/images/creatures/crusher/krosh_rock.sprite +++ b/data/images/creatures/crusher/krosh_rock.sprite @@ -18,18 +18,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 4 4 128 128) - (images "krosh_rock_whites.png") + (images "krosh_rock_lefteye.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 4 4 128 128) - (images "krosh_rock_lefteye.png") + (images "krosh_rock_righteye.png") ) (action - (name "righteye") + (name "whites") (hitbox 4 4 128 128) - (images "krosh_rock_righteye.png") + (images "krosh_rock_whites.png") + ) + + (linked-sprites + (left-eye "krosh_rock.sprite" "left-eye") + (right-eye "krosh_rock.sprite" "right-eye") + (whites "krosh_rock.sprite" "whites") ) ) diff --git a/data/images/creatures/crusher/krush_ice.sprite b/data/images/creatures/crusher/krush_ice.sprite index 622eaacbd76..f35d6a4798a 100644 --- a/data/images/creatures/crusher/krush_ice.sprite +++ b/data/images/creatures/crusher/krush_ice.sprite @@ -18,18 +18,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 3 3 64 64) - (images "krush_ice_whites.png") + (images "krush_ice_lefteye.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 3 3 64 64) - (images "krush_ice_lefteye.png") + (images "krush_ice_righteye.png") ) (action - (name "righteye") + (name "whites") (hitbox 3 3 64 64) - (images "krush_ice_righteye.png") + (images "krush_ice_whites.png") + ) + + (linked-sprites + (left-eye "krush_ice.sprite" "left-eye") + (right-eye "krush_ice.sprite" "right-eye") + (whites "krush_ice.sprite" "whites") ) ) diff --git a/data/images/creatures/crusher/krush_rock.sprite b/data/images/creatures/crusher/krush_rock.sprite index b38e4809690..b521f255984 100644 --- a/data/images/creatures/crusher/krush_rock.sprite +++ b/data/images/creatures/crusher/krush_rock.sprite @@ -20,18 +20,24 @@ ) ) (action - (name "whites") + (name "left-eye") (hitbox 3 3 64 64) - (images "krush_rock_whites.png") + (images "krush_rock_lefteye.png") ) (action - (name "lefteye") + (name "right-eye") (hitbox 3 3 64 64) - (images "krush_rock_lefteye.png") + (images "krush_rock_righteye.png") ) (action - (name "righteye") + (name "whites") (hitbox 3 3 64 64) - (images "krush_rock_righteye.png") + (images "krush_rock_whites.png") + ) + + (linked-sprites + (left-eye "krush_rock.sprite" "left-eye") + (right-eye "krush_rock.sprite" "right-eye") + (whites "krush_rock.sprite" "whites") ) ) diff --git a/data/images/creatures/darttrap/granito/dart_light.sprite b/data/images/creatures/darttrap/granito/dart_light.sprite new file mode 100644 index 00000000000..8b103c7872b --- /dev/null +++ b/data/images/creatures/darttrap/granito/dart_light.sprite @@ -0,0 +1,7 @@ +(supertux-sprite + (action + (name "default") + (hitbox 16 16 0 0) + (images "dart_light.png") + ) +) diff --git a/data/images/creatures/darttrap/granito/root_dart.sprite b/data/images/creatures/darttrap/granito/root_dart.sprite index a9dc94d6b2d..f47f5880690 100644 --- a/data/images/creatures/darttrap/granito/root_dart.sprite +++ b/data/images/creatures/darttrap/granito/root_dart.sprite @@ -3,20 +3,24 @@ (name "flying-left") (hitbox 6 13 20 8) (images "root_dart_left.png") - ) + ) (action (name "flying-right") (hitbox 6 13 20 8) (mirror-action "flying-left") - ) + ) (action (name "flying-down") (hitbox 13 6 8 20) (images "root_dart_down.png") - ) + ) (action (name "flying-up") (hitbox 13 6 8 20) (flip-action "flying-down") - ) ) + + (linked-sprites + (light "dart_light.sprite" "" 1 1 1) + ) +) diff --git a/data/images/creatures/darttrap/skull/dart_light.sprite b/data/images/creatures/darttrap/skull/dart_light.sprite new file mode 100644 index 00000000000..8b103c7872b --- /dev/null +++ b/data/images/creatures/darttrap/skull/dart_light.sprite @@ -0,0 +1,7 @@ +(supertux-sprite + (action + (name "default") + (hitbox 16 16 0 0) + (images "dart_light.png") + ) +) diff --git a/data/images/creatures/darttrap/skull/skull_dart.sprite b/data/images/creatures/darttrap/skull/skull_dart.sprite index ffae418de3d..342563acfe7 100644 --- a/data/images/creatures/darttrap/skull/skull_dart.sprite +++ b/data/images/creatures/darttrap/skull/skull_dart.sprite @@ -19,4 +19,8 @@ (hitbox 12 6 9 22) (flip-action "flying-down") ) -) \ No newline at end of file + + (linked-sprites + (light "dart_light.sprite" "" 1 1 1) + ) +) diff --git a/data/images/creatures/dive_mine/dive_mine.sprite b/data/images/creatures/dive_mine/dive_mine.sprite index 370b9b89589..5399ae6f7c3 100644 --- a/data/images/creatures/dive_mine/dive_mine.sprite +++ b/data/images/creatures/dive_mine/dive_mine.sprite @@ -29,13 +29,16 @@ (action (name "iced-right") - (hitbox 6 13 45 43) + (hitbox 10 13 45 43) (mirror-action "iced-left")) (action (name "ticking-left") (fps 15.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "ticking") + ) (images "ticking-0.png" "ticking-1.png" "ticking-2.png" @@ -45,14 +48,19 @@ "ticking-6.png" "ticking-7.png" "ticking-8.png" - "ticking-9.png" - )) + "ticking-9.png")) (action (name "ticking-right") (fps 15.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "ticking") + ) (mirror-action "ticking-left")) - -) + + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "idle") + ) +) \ No newline at end of file diff --git a/data/images/creatures/flame/flame.sprite b/data/images/creatures/flame/flame.sprite index f2932799265..6b17c4c697e 100644 --- a/data/images/creatures/flame/flame.sprite +++ b/data/images/creatures/flame/flame.sprite @@ -13,5 +13,10 @@ "flame-fade-1.png" "flame-fade-2.png" "flame-fade-3.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "" 0.21 0.13 0.08) + (smoke "images/particles/smoke.sprite") + ) ) diff --git a/data/images/creatures/flame/ghostflame.sprite b/data/images/creatures/flame/ghostflame.sprite index 4066b0c81cb..aa559dbdb70 100644 --- a/data/images/creatures/flame/ghostflame.sprite +++ b/data/images/creatures/flame/ghostflame.sprite @@ -7,5 +7,10 @@ "ghostflame-2.png" "ghostflame-3.png" "ghostflame-4.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "" 0.21 0 0.21) + (smoke "images/particles/smoke.sprite") + ) ) diff --git a/data/images/creatures/flame/iceflame.sprite b/data/images/creatures/flame/iceflame.sprite index dd3eca9ad32..5e3e7d4167d 100644 --- a/data/images/creatures/flame/iceflame.sprite +++ b/data/images/creatures/flame/iceflame.sprite @@ -10,5 +10,10 @@ (images "iceflame-fade-0.png" "iceflame-fade-1.png" "iceflame-fade-2.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "" 0 0.13 0.18) + (smoke "images/particles/smoke.sprite") + ) ) diff --git a/data/images/creatures/flying_snowball/flying_snowball.sprite b/data/images/creatures/flying_snowball/flying_snowball.sprite index 4995aeabafb..4b9ec226852 100644 --- a/data/images/creatures/flying_snowball/flying_snowball.sprite +++ b/data/images/creatures/flying_snowball/flying_snowball.sprite @@ -37,4 +37,8 @@ (fps 20) (hitbox 8 8 32 32) (mirror-action "melting-left")) + + (linked-sprites + (smoke "images/particles/smoke.sprite") + ) ) diff --git a/data/images/creatures/ghosttree/ghosttree.sprite b/data/images/creatures/ghosttree/ghosttree.sprite index 7c72c5b38c3..d231623295b 100644 --- a/data/images/creatures/ghosttree/ghosttree.sprite +++ b/data/images/creatures/ghosttree/ghosttree.sprite @@ -21,6 +21,9 @@ (name "dying") (hitbox 230 300 40 60) (fps 4) + (linked-sprites + (glow "ghosttree-glow.sprite" "dying" 1) + ) (images "ghosttree-dying-0.png" "ghosttree-dying-0.png" @@ -28,4 +31,8 @@ "ghosttree-dying-0.png" ) ) + + (linked-sprites + (glow "ghosttree-glow.sprite") + ) ) diff --git a/data/images/creatures/ghosttree/root.sprite b/data/images/creatures/ghosttree/root.sprite index 7e54ff1feb7..8d7765738a7 100644 --- a/data/images/creatures/ghosttree/root.sprite +++ b/data/images/creatures/ghosttree/root.sprite @@ -3,4 +3,8 @@ (name "default") (images "root.png") ) + + (linked-sprites + (base "root_base.sprite") + ) ) diff --git a/data/images/creatures/gold_bomb/gold_bomb.sprite b/data/images/creatures/gold_bomb/gold_bomb.sprite index 53e48c7c1d1..3b0d042581b 100644 --- a/data/images/creatures/gold_bomb/gold_bomb.sprite +++ b/data/images/creatures/gold_bomb/gold_bomb.sprite @@ -177,5 +177,8 @@ (loops 1) (hitbox 14 19 32 32) (mirror-action "ticking-left")) - + + (linked-sprites + (ticking-glow "images/creatures/mr_bomb/ticking_glow/ticking_glow.sprite") + ) ) diff --git a/data/images/creatures/granito/corrupted/big/rock_mine.sprite b/data/images/creatures/granito/corrupted/big/rock_mine.sprite index 1f46b1f58f8..18787b1fc87 100644 --- a/data/images/creatures/granito/corrupted/big/rock_mine.sprite +++ b/data/images/creatures/granito/corrupted/big/rock_mine.sprite @@ -40,4 +40,9 @@ (hitbox 18 26 48 48) (mirror-action "broken-left") ) + + (linked-sprites + (rock-particles "images/particles/granito_piece.sprite") + (shard "root_spike.sprite") + ) ) diff --git a/data/images/creatures/haywire/haywire.sprite b/data/images/creatures/haywire/haywire.sprite index 11b379afd47..2c944faad86 100644 --- a/data/images/creatures/haywire/haywire.sprite +++ b/data/images/creatures/haywire/haywire.sprite @@ -32,6 +32,9 @@ (name "ticking-left") (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "run") + ) (images "chase-0.png" "chase-1.png" "chase-2.png" @@ -44,6 +47,9 @@ (name "ticking-right") (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "run") + ) (mirror-action "ticking-left")) (action @@ -78,6 +84,9 @@ (loops 1) (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "skid" 1) + ) (images "skid-0.png" "skid-1.png" "skid-2.png" @@ -88,6 +97,9 @@ (loops 1) (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "skid" 1) + ) (mirror-action "skid-left")) (action @@ -95,6 +107,9 @@ (loops 1) (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "jump" 1) + ) (images "jump-0.png" "jump-1.png" "jump-2.png" @@ -105,5 +120,12 @@ (loops 1) (fps 20.0) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "jump" 1) + ) (mirror-action "jump-left")) + + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite") + ) ) diff --git a/data/images/creatures/kugelblitz/kugelblitz.sprite b/data/images/creatures/kugelblitz/kugelblitz.sprite index e29cc4c7cb0..ccd78fdab29 100644 --- a/data/images/creatures/kugelblitz/kugelblitz.sprite +++ b/data/images/creatures/kugelblitz/kugelblitz.sprite @@ -21,4 +21,8 @@ "pop-1.png" "pop-2.png" "pop-3.png")) -) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light.sprite" "default" 0.2 0.1 0) + ) +) diff --git a/data/images/creatures/livefire/livefire.sprite b/data/images/creatures/livefire/livefire.sprite index a3e476e827f..0422cce0440 100644 --- a/data/images/creatures/livefire/livefire.sprite +++ b/data/images/creatures/livefire/livefire.sprite @@ -60,4 +60,9 @@ (fps 14) (hitbox 20 18 40 40) (mirror-action "extinguish-left")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-medium.sprite" "" 0.89 0.75 0.44) + (smoke "images/particles/smoke.sprite") + ) ) diff --git a/data/images/creatures/mole/corrupted/root.sprite b/data/images/creatures/mole/corrupted/root.sprite index 9d51198fbe6..c1124854213 100644 --- a/data/images/creatures/mole/corrupted/root.sprite +++ b/data/images/creatures/mole/corrupted/root.sprite @@ -39,4 +39,8 @@ (name "base-right") (hitbox 9 22 80 16) (mirror-action "base-left")) -) \ No newline at end of file + + (linked-sprites + (rock "images/particles/corrupted_rock.sprite") + ) +) diff --git a/data/images/creatures/mole/corrupted/root_sapling.sprite b/data/images/creatures/mole/corrupted/root_sapling.sprite index a7f48cbef38..501821828e2 100644 --- a/data/images/creatures/mole/corrupted/root_sapling.sprite +++ b/data/images/creatures/mole/corrupted/root_sapling.sprite @@ -93,4 +93,8 @@ (hitbox 70 24 32 32) (mirror-action "squished-left") ) + + (linked-sprites + (light "core_glow/core_glow.sprite") + ) ) diff --git a/data/images/creatures/mr_bomb/mr_bomb.sprite b/data/images/creatures/mr_bomb/mr_bomb.sprite index 56e466ba18a..143878cdf86 100644 --- a/data/images/creatures/mr_bomb/mr_bomb.sprite +++ b/data/images/creatures/mr_bomb/mr_bomb.sprite @@ -33,6 +33,9 @@ (fps 15.0) (loops 1) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "exploding") + ) (images "ticking-0.png" "ticking-1.png" "ticking-2.png" @@ -107,6 +110,12 @@ (fps 15.0) (loops 1) (hitbox 14 19 32 32) + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite" "exploding" 1) + ) (mirror-action "ticking-left")) - + + (linked-sprites + (ticking-glow "ticking_glow/ticking_glow.sprite") + ) ) diff --git a/data/images/creatures/mr_candle/mr-candle.sprite b/data/images/creatures/mr_candle/mr-candle.sprite index 9429355e3d4..26017ad16f8 100644 --- a/data/images/creatures/mr_candle/mr-candle.sprite +++ b/data/images/creatures/mr_candle/mr-candle.sprite @@ -27,5 +27,9 @@ (name "iced-right") (hitbox 26 35 45 43) (mirror-action "iced-left") - ) + ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-medium.sprite") + ) ) diff --git a/data/images/creatures/mr_tree/mr_tree.sprite b/data/images/creatures/mr_tree/mr_tree.sprite index 3f6cd38b00b..7a0aea68fe9 100644 --- a/data/images/creatures/mr_tree/mr_tree.sprite +++ b/data/images/creatures/mr_tree/mr_tree.sprite @@ -52,4 +52,8 @@ (name "iced-right") (mirror-action "iced-left") ) + + (linked-sprites + (leaf "images/particles/leaf.sprite") + ) ) diff --git a/data/images/creatures/mr_tree/stumpy.sprite b/data/images/creatures/mr_tree/stumpy.sprite index 1c80decf4b5..6d9c2c02420 100644 --- a/data/images/creatures/mr_tree/stumpy.sprite +++ b/data/images/creatures/mr_tree/stumpy.sprite @@ -82,4 +82,8 @@ (name "squished-right") (mirror-action "squished-left") ) + + (linked-sprites + (bark "images/particles/bark.sprite") + ) ) diff --git a/data/images/creatures/tux/tux.sprite b/data/images/creatures/tux/tux.sprite index 8bd0bc704ee..361dd46a830 100644 --- a/data/images/creatures/tux/tux.sprite +++ b/data/images/creatures/tux/tux.sprite @@ -3057,4 +3057,9 @@ (fps 10.0) (hitbox 16 14 32 64) (mirror-action "credits-right")) + + (linked-sprites + (sparkle-invincible "images/particles/sparkle.sprite") + (rock-particle "images/particles/rock.sprite") + ) ) diff --git a/data/images/creatures/willowisp/willowisp.sprite b/data/images/creatures/willowisp/willowisp.sprite index 9408787fdbe..d43386e56b9 100644 --- a/data/images/creatures/willowisp/willowisp.sprite +++ b/data/images/creatures/willowisp/willowisp.sprite @@ -31,5 +31,9 @@ "warping-5.png" ) ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite") ) +) diff --git a/data/images/objects/big_snowball/big_snowball.sprite b/data/images/objects/big_snowball/big_snowball.sprite index 73ea8fd4c4b..e6b26fe300e 100644 --- a/data/images/objects/big_snowball/big_snowball.sprite +++ b/data/images/objects/big_snowball/big_snowball.sprite @@ -8,4 +8,8 @@ (name "particle") (hitbox 2 2 29 28) (images "big_snowball_particle.png")) + + (linked-sprites + (particle "big_snowball.sprite" "particle") + ) ) diff --git a/data/images/objects/bonus_block/bonusblock.sprite b/data/images/objects/bonus_block/bonusblock.sprite index 92e1894d9dd..0e57566692b 100644 --- a/data/images/objects/bonus_block/bonusblock.sprite +++ b/data/images/objects/bonus_block/bonusblock.sprite @@ -29,4 +29,8 @@ (action (name "off") (images "lightblock_off.png")) + + (linked-sprites + (on-light "images/objects/lightmap_light/bonusblock_light.png") + ) ) diff --git a/data/images/objects/bonus_block/brick.sprite b/data/images/objects/bonus_block/brick.sprite index 0d8989344e6..217c2e0c612 100644 --- a/data/images/objects/bonus_block/brick.sprite +++ b/data/images/objects/bonus_block/brick.sprite @@ -39,4 +39,8 @@ (name "piece6") (fps 1) (images "../../tiles/blocks/brick_piece6.png")) - ) + + (linked-sprites + (break-particles "brick.sprite") + ) +) diff --git a/data/images/objects/bonus_block/brickIce.sprite b/data/images/objects/bonus_block/brickIce.sprite index 22a1e8ba6e5..a4afad6c1fc 100644 --- a/data/images/objects/bonus_block/brickIce.sprite +++ b/data/images/objects/bonus_block/brickIce.sprite @@ -10,33 +10,7 @@ (name "normal") (images "../../tiles/blocks/brick1.png")) - (action - (name "piece1") - (fps 1) - (images "../../tiles/blocks/brick_piece1.png")) - - (action - (name "piece2") - (fps 1) - (images "../../tiles/blocks/brick_piece2.png")) - - (action - (name "piece3") - (fps 1) - (images "../../tiles/blocks/brick_piece3.png")) - - (action - (name "piece4") - (fps 1) - (images "../../tiles/blocks/brick_piece4.png")) - - (action - (name "piece5") - (fps 1) - (images "../../tiles/blocks/brick_piece5.png")) - - (action - (name "piece6") - (fps 1) - (images "../../tiles/blocks/brick_piece6.png")) + (linked-sprites + (break-particles "brick.sprite") + ) ) diff --git a/data/images/objects/bonus_block/brickWeb.sprite b/data/images/objects/bonus_block/brickWeb.sprite index a01557a9049..4e44441e466 100644 --- a/data/images/objects/bonus_block/brickWeb.sprite +++ b/data/images/objects/bonus_block/brickWeb.sprite @@ -10,33 +10,7 @@ (name "normal") (images "../../tiles/blocks/brick2.png")) - (action - (name "piece1") - (fps 1) - (images "../../tiles/blocks/brick_piece1.png")) - - (action - (name "piece2") - (fps 1) - (images "../../tiles/blocks/brick_piece2.png")) - - (action - (name "piece3") - (fps 1) - (images "../../tiles/blocks/brick_piece3.png")) - - (action - (name "piece4") - (fps 1) - (images "../../tiles/blocks/brick_piece4.png")) - - (action - (name "piece5") - (fps 1) - (images "../../tiles/blocks/brick_piece5.png")) - - (action - (name "piece6") - (fps 1) - (images "../../tiles/blocks/brick_piece6.png")) + (linked-sprites + (break-particles "brick.sprite") + ) ) diff --git a/data/images/objects/bonus_block/heavy-brick.sprite b/data/images/objects/bonus_block/heavy-brick.sprite index 72a8834747b..56ceb2ce3e1 100644 --- a/data/images/objects/bonus_block/heavy-brick.sprite +++ b/data/images/objects/bonus_block/heavy-brick.sprite @@ -39,4 +39,8 @@ (name "piece6") (fps 1) (images "../../tiles/blocks/brick_piece12.png")) + + (linked-sprites + (break-particles "heavy-brick.sprite") + ) ) diff --git a/data/images/objects/bonus_block/orangeblock.sprite b/data/images/objects/bonus_block/orangeblock.sprite index 95dfc235e08..e884cfe874d 100644 --- a/data/images/objects/bonus_block/orangeblock.sprite +++ b/data/images/objects/bonus_block/orangeblock.sprite @@ -19,4 +19,8 @@ (surface (diffuse-texture (file "orange_empty.png")) (displacement-texture (file "displacement.png"))))) + + (linked-sprites + (on-light "images/objects/lightmap_light/bonusblock_light.png") + ) ) diff --git a/data/images/objects/bonus_block/purpleblock.sprite b/data/images/objects/bonus_block/purpleblock.sprite index 2301e43623b..ed771016f16 100644 --- a/data/images/objects/bonus_block/purpleblock.sprite +++ b/data/images/objects/bonus_block/purpleblock.sprite @@ -19,4 +19,8 @@ (surface (diffuse-texture (file "purple_empty.png")) (displacement-texture (file "displacement.png"))))) + + (linked-sprites + (on-light "images/objects/lightmap_light/bonusblock_light.png") + ) ) diff --git a/data/images/objects/bonus_block/retroblock.sprite b/data/images/objects/bonus_block/retroblock.sprite index b5b79a4d556..19281347468 100644 --- a/data/images/objects/bonus_block/retroblock.sprite +++ b/data/images/objects/bonus_block/retroblock.sprite @@ -10,4 +10,8 @@ (surface (diffuse-texture (file "box-empty.png")) (displacement-texture (file "displacement.png"))))) + + (linked-sprites + (on-light "images/objects/lightmap_light/bonusblock_light.png") + ) ) diff --git a/data/images/objects/bullets/firebullet.sprite b/data/images/objects/bullets/firebullet.sprite index dafa1f74683..bb82049fc83 100644 --- a/data/images/objects/bullets/firebullet.sprite +++ b/data/images/objects/bullets/firebullet.sprite @@ -7,4 +7,8 @@ "fire_bullet-2.png" "fire_bullet-3.png") ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0.3 0.1 0) + ) ) diff --git a/data/images/objects/candle/candle.sprite b/data/images/objects/candle/candle.sprite index cb566437114..92fc273fd9e 100644 --- a/data/images/objects/candle/candle.sprite +++ b/data/images/objects/candle/candle.sprite @@ -10,6 +10,21 @@ "candle-4.png" ) ) + (action + (name "on-white") + (hitbox 2 22 32 32) + (fps 16) + (linked-sprites + (light-1 "candle-light-1.sprite" "white") + (light-2 "candle-light-2.sprite" "white") + ) + (images + "candle-1.png" + "candle-2.png" + "candle-3.png" + "candle-4.png" + ) + ) (action (name "off") (hitbox 2 22 32 32) @@ -18,5 +33,25 @@ "candle-0.png" ) ) -) + (action + (name "off-white") + (hitbox 2 22 32 32) + (fps 16) + (linked-sprites + (light-1 "candle-light-1.sprite" "white") + (light-2 "candle-light-2.sprite" "white") + ) + (images + "candle-1.png" + "candle-2.png" + "candle-3.png" + "candle-4.png" + ) + ) + (linked-sprites + (light-1 "candle-light-1.sprite") + (light-2 "candle-light-2.sprite") + (smoke "images/particles/smoke.sprite") + ) +) diff --git a/data/images/objects/door/door.sprite b/data/images/objects/door/door.sprite index d62e4b84916..08c19bb6043 100644 --- a/data/images/objects/door/door.sprite +++ b/data/images/objects/door/door.sprite @@ -41,4 +41,8 @@ "door-1.png" "door-0.png") ) + + (linked-sprites + (lock "door_lock.sprite") + ) ) diff --git a/data/images/objects/explosion/explosion.sprite b/data/images/objects/explosion/explosion_large.sprite similarity index 82% rename from data/images/objects/explosion/explosion.sprite rename to data/images/objects/explosion/explosion_large.sprite index 115e1d8490e..3a65a145d09 100644 --- a/data/images/objects/explosion/explosion.sprite +++ b/data/images/objects/explosion/explosion_large.sprite @@ -25,5 +25,8 @@ (hitbox 0 0 48 48) (images "pop-0.png") ) -) + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-large.sprite" "default" 1 0.5 0.2) + ) +) diff --git a/data/images/objects/explosion/explosion_medium.sprite b/data/images/objects/explosion/explosion_medium.sprite new file mode 100644 index 00000000000..bf99260b5e3 --- /dev/null +++ b/data/images/objects/explosion/explosion_medium.sprite @@ -0,0 +1,32 @@ +(supertux-sprite + (action + (name "default") + (fps 15.0) + (hitbox 36 36 48 48) + (images + "explosion-0.png" + "explosion-1.png" + "explosion-2.png" + "explosion-3.png" + "explosion-4.png" + "explosion-5.png" + "explosion-6.png" + "explosion-7.png" + "explosion-8.png" + "explosion-9.png" + "explosion-10.png" + "explosion-11.png" + "explosion-12.png" + ) + ) + (action + (name "pop") + (fps 2) + (hitbox 0 0 48 48) + (images "pop-0.png") + ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-medium.sprite" "default" 1 0.5 0.2) + ) +) diff --git a/data/images/objects/firefly/firefly.sprite b/data/images/objects/firefly/firefly.sprite index fd6ac33339b..8049e866b91 100644 --- a/data/images/objects/firefly/firefly.sprite +++ b/data/images/objects/firefly/firefly.sprite @@ -24,5 +24,8 @@ "firefly6.png" ) - ) + ) + (linked-sprites + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/keys/key.sprite b/data/images/objects/keys/key.sprite index 93dcffa763b..757fff04ae2 100644 --- a/data/images/objects/keys/key.sprite +++ b/data/images/objects/keys/key.sprite @@ -8,4 +8,10 @@ (name "silver-left") (hitbox 0 2 48 28) (mirror-action "silver-right")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite") + (sparkle-small "images/particles/sparkle.sprite" "small") + (sparkle-collect "images/particles/sparkle.sprite" "small-key-collect") + ) ) diff --git a/data/images/objects/lantern/lantern.sprite b/data/images/objects/lantern/lantern.sprite index cfe4c5b614f..1ab57ddb589 100644 --- a/data/images/objects/lantern/lantern.sprite +++ b/data/images/objects/lantern/lantern.sprite @@ -20,4 +20,8 @@ (hitbox 8 28 34 39) (images "lantern-1.png") ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light.sprite") + ) ) diff --git a/data/images/objects/resetpoints/bell.sprite b/data/images/objects/resetpoints/bell.sprite index 94f1da2d63d..b3e4203a419 100644 --- a/data/images/objects/resetpoints/bell.sprite +++ b/data/images/objects/resetpoints/bell.sprite @@ -18,4 +18,7 @@ ) (hitbox 8 5 32 32) ) + (linked-sprites + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/resetpoints/default-resetpoint.sprite b/data/images/objects/resetpoints/default-resetpoint.sprite index 94f1da2d63d..b3e4203a419 100644 --- a/data/images/objects/resetpoints/default-resetpoint.sprite +++ b/data/images/objects/resetpoints/default-resetpoint.sprite @@ -18,4 +18,7 @@ ) (hitbox 8 5 32 32) ) + (linked-sprites + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/resetpoints/firefly.sprite b/data/images/objects/resetpoints/firefly.sprite index 08dea16f213..fa062684e42 100644 --- a/data/images/objects/resetpoints/firefly.sprite +++ b/data/images/objects/resetpoints/firefly.sprite @@ -18,5 +18,8 @@ "firefly6.png" ) - ) + ) + (linked-sprites + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/resetpoints/torch.sprite b/data/images/objects/resetpoints/torch.sprite index 0e2a37f8f1b..5fc8e7494cc 100644 --- a/data/images/objects/resetpoints/torch.sprite +++ b/data/images/objects/resetpoints/torch.sprite @@ -24,5 +24,10 @@ "torch6.png" ) - ) + ) + + (linked-sprites + (light "torch_light.sprite" "default" 0.87 0.64 0.12) + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/resetpoints/torch_light.sprite b/data/images/objects/resetpoints/torch_light.sprite new file mode 100644 index 00000000000..b0d7258071e --- /dev/null +++ b/data/images/objects/resetpoints/torch_light.sprite @@ -0,0 +1,8 @@ +(supertux-sprite + (action + (name "default") + (images "../lightmap_light/lightmap_light-small.png") + (hitbox 64 76 0 0) + (flip-offset 48) + ) +) diff --git a/data/images/objects/resetpoints/vbell.sprite b/data/images/objects/resetpoints/vbell.sprite index f15536cb310..6d2a7e58c42 100644 --- a/data/images/objects/resetpoints/vbell.sprite +++ b/data/images/objects/resetpoints/vbell.sprite @@ -17,5 +17,8 @@ "vbell-r_0.png" "vbell-m.png" ) - ) + ) + (linked-sprites + (reset "images/particles/reset.sprite") + ) ) diff --git a/data/images/objects/rublight/rublight.sprite b/data/images/objects/rublight/rublight.sprite index 323f1057f14..80fab52ff15 100644 --- a/data/images/objects/rublight/rublight.sprite +++ b/data/images/objects/rublight/rublight.sprite @@ -19,4 +19,8 @@ (name "inactive") (images "rublight-0.png") ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light.sprite") + ) ) diff --git a/data/images/objects/torch/torch1.sprite b/data/images/objects/torch/torch1.sprite index 0b047284981..8f43182aaae 100644 --- a/data/images/objects/torch/torch1.sprite +++ b/data/images/objects/torch/torch1.sprite @@ -4,4 +4,10 @@ (hitbox 0 0 16 100) (images "torch1.png") ) + + (linked-sprites + (flame "flame.sprite") + (glow "flame_glow.sprite") + (light "flame_light.sprite") + ) ) diff --git a/data/images/objects/torch/torch2.sprite b/data/images/objects/torch/torch2.sprite index 335bf7588fc..c570ecc1a09 100644 --- a/data/images/objects/torch/torch2.sprite +++ b/data/images/objects/torch/torch2.sprite @@ -4,4 +4,10 @@ (hitbox 0 0 16 100) (images "torch2.png") ) + + (linked-sprites + (flame "flame.sprite") + (glow "flame_glow.sprite") + (light "flame_light.sprite") + ) ) diff --git a/data/images/objects/torch/torch3.sprite b/data/images/objects/torch/torch3.sprite index b552b36b407..c698d6a9a85 100644 --- a/data/images/objects/torch/torch3.sprite +++ b/data/images/objects/torch/torch3.sprite @@ -4,4 +4,10 @@ (hitbox 0 0 16 100) (images "torch3.png") ) + + (linked-sprites + (flame "flame.sprite") + (glow "flame_glow.sprite") + (light "flame_light.sprite") + ) ) diff --git a/data/images/objects/torch/torch4.sprite b/data/images/objects/torch/torch4.sprite index 6b47dfefd84..a1d785bafab 100644 --- a/data/images/objects/torch/torch4.sprite +++ b/data/images/objects/torch/torch4.sprite @@ -4,4 +4,10 @@ (hitbox 0 0 16 100) (images "torch4.png") ) + + (linked-sprites + (flame "flame.sprite") + (glow "flame_glow.sprite") + (light "flame_light.sprite") + ) ) diff --git a/data/images/objects/weak_block/strawbox.sprite b/data/images/objects/weak_block/strawbox.sprite index fb2689642b4..6e42003dd9a 100644 --- a/data/images/objects/weak_block/strawbox.sprite +++ b/data/images/objects/weak_block/strawbox.sprite @@ -30,4 +30,8 @@ "strawbox-11.png" ) ) + + (linked-sprites + (burn-light "images/objects/lightmap_light/lightmap_light-small.sprite") + ) ) diff --git a/data/images/particles/sparkle.sprite b/data/images/particles/sparkle.sprite index 05ea11f6e53..f6b09b48014 100644 --- a/data/images/particles/sparkle.sprite +++ b/data/images/particles/sparkle.sprite @@ -23,6 +23,9 @@ "sparkle-dark-1.png" "sparkle-dark-0.png" ) + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-tiny.sprite" "" 0.1 0.1 0.1) + ) ) (action (name "medium") @@ -34,4 +37,8 @@ "sparkle-0.png" ) ) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-tiny.sprite") + ) ) diff --git a/data/images/powerups/airflower/airflower.sprite b/data/images/powerups/airflower/airflower.sprite index dda2e51b8f4..004045199eb 100644 --- a/data/images/powerups/airflower/airflower.sprite +++ b/data/images/powerups/airflower/airflower.sprite @@ -6,4 +6,9 @@ "air_flower-2.png" "air_flower-3.png" "air_flower-2.png" - "air_flower-1.png"))) + "air_flower-1.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0.15 0 0.15) + ) +) diff --git a/data/images/powerups/earthflower/earthflower.sprite b/data/images/powerups/earthflower/earthflower.sprite index 213993e1511..6ad70243108 100644 --- a/data/images/powerups/earthflower/earthflower.sprite +++ b/data/images/powerups/earthflower/earthflower.sprite @@ -6,4 +6,9 @@ "earth_flower-2.png" "earth_flower-3.png" "earth_flower-2.png" - "earth_flower-1.png"))) + "earth_flower-1.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0 0.3 0) + ) +) diff --git a/data/images/powerups/egg/egg.sprite b/data/images/powerups/egg/egg.sprite index 61959ad86b6..53377f80493 100644 --- a/data/images/powerups/egg/egg.sprite +++ b/data/images/powerups/egg/egg.sprite @@ -7,4 +7,9 @@ (name "shadow") (images "egg-shade.png") ) + + (linked-sprites + (shade "egg.sprite" "shadow") + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0.2 0.2 0) + ) ) diff --git a/data/images/powerups/fireflower/fireflower.sprite b/data/images/powerups/fireflower/fireflower.sprite index 72b8481441b..5cf51d1d03e 100644 --- a/data/images/powerups/fireflower/fireflower.sprite +++ b/data/images/powerups/fireflower/fireflower.sprite @@ -6,4 +6,9 @@ "fire_flower-2.png" "fire_flower-3.png" "fire_flower-2.png" - "fire_flower-1.png"))) + "fire_flower-1.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0.3 0 0) + ) +) diff --git a/data/images/powerups/iceflower/iceflower.sprite b/data/images/powerups/iceflower/iceflower.sprite index e9812899aca..6d80b953e2d 100644 --- a/data/images/powerups/iceflower/iceflower.sprite +++ b/data/images/powerups/iceflower/iceflower.sprite @@ -6,4 +6,9 @@ "ice_flower-2.png" "ice_flower-3.png" "ice_flower-2.png" - "ice_flower-1.png"))) + "ice_flower-1.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0 0.1 0.2) + ) +) diff --git a/data/images/powerups/star/star.sprite b/data/images/powerups/star/star.sprite index a37b4fdaeb5..670a5663c6a 100644 --- a/data/images/powerups/star/star.sprite +++ b/data/images/powerups/star/star.sprite @@ -8,4 +8,10 @@ "star-4.png" "star-3.png" "star-2.png" - "star-1.png"))) + "star-1.png")) + + (linked-sprites + (light "images/objects/lightmap_light/lightmap_light-small.sprite" "default" 0.4 0.4 0.4) + (sparkle "images/particles/sparkle.sprite") + ) +) diff --git a/external/sexp-cpp b/external/sexp-cpp index 6018831abc1..ece5200d1e7 160000 --- a/external/sexp-cpp +++ b/external/sexp-cpp @@ -1 +1 @@ -Subproject commit 6018831abc1e5d5020c7b62f99962806dacf4c9f +Subproject commit ece5200d1e79c72c927143ebef87ce05cd1ff32d diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index aa698a6987c..6464b52ba00 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -46,13 +46,13 @@ static const float X_OFFSCREEN_DISTANCE = 1280; static const float Y_OFFSCREEN_DISTANCE = 800; BadGuy::BadGuy(const Vector& pos, const std::string& sprite_name, int layer, - const std::string& light_sprite_name, const std::string& ice_sprite_name) : - BadGuy(pos, Direction::LEFT, sprite_name, layer, light_sprite_name) + const std::string& burn_light_sprite_name, const std::string& ice_sprite_name) : + BadGuy(pos, Direction::LEFT, sprite_name, layer, burn_light_sprite_name) { } BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite_name, int layer, - const std::string& light_sprite_name, const std::string& ice_sprite_name) : + const std::string& burn_light_sprite_name, const std::string& ice_sprite_name) : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), m_physic(), m_countMe(true), @@ -65,9 +65,9 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite m_in_water(false), m_dead_script(), m_melting_time(0), - m_lightsprite(SpriteManager::current()->create(light_sprite_name)), + m_burn_light_sprite(SpriteManager::current()->create(burn_light_sprite_name)), m_freezesprite(SpriteManager::current()->create(ice_sprite_name)), - m_glowing(false), + m_burning(false), m_water_affected(true), m_unfreeze_timer(), m_state(STATE_INIT), @@ -84,18 +84,18 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite SoundManager::current()->preload("sounds/fire.ogg"); m_dir = (m_start_dir == Direction::AUTO) ? Direction::LEFT : m_start_dir; - m_lightsprite->set_blend(Blend::ADD); + m_burn_light_sprite->set_blend(Blend::ADD); } BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, int layer, - const std::string& light_sprite_name, const std::string& ice_sprite_name) : - BadGuy(reader, sprite_name, Direction::AUTO, layer, light_sprite_name, ice_sprite_name) + const std::string& burn_light_sprite_name, const std::string& ice_sprite_name) : + BadGuy(reader, sprite_name, Direction::AUTO, layer, burn_light_sprite_name, ice_sprite_name) { } BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, Direction default_direction, int layer, - const std::string& light_sprite_name, const std::string& ice_sprite_name) : + const std::string& burn_light_sprite_name, const std::string& ice_sprite_name) : MovingSprite(reader, sprite_name, layer, COLGROUP_DISABLED), m_physic(), m_countMe(true), @@ -108,9 +108,9 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, m_in_water(false), m_dead_script(), m_melting_time(0), - m_lightsprite(SpriteManager::current()->create(light_sprite_name)), + m_burn_light_sprite(SpriteManager::current()->create(burn_light_sprite_name)), m_freezesprite(SpriteManager::current()->create(ice_sprite_name)), - m_glowing(false), + m_burning(false), m_water_affected(true), m_unfreeze_timer(), m_state(STATE_INIT), @@ -134,7 +134,7 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name, SoundManager::current()->preload("sounds/fire.ogg"); m_dir = (m_start_dir == Direction::AUTO) ? Direction::LEFT : m_start_dir; - m_lightsprite->set_blend(Blend::ADD); + m_burn_light_sprite->set_blend(Blend::ADD); } void @@ -147,9 +147,8 @@ BadGuy::draw(DrawingContext& context) if (m_state == STATE_INIT || m_state == STATE_INACTIVE) { - if (Editor::is_active()) { - m_sprite->draw(context.color(), draw_pos, m_layer, m_flip); - } + if (Editor::is_active()) + MovingSprite::draw(context); } else { @@ -157,7 +156,7 @@ BadGuy::draw(DrawingContext& context) { context.push_transform(); context.set_flip(context.get_flip() ^ VERTICAL_FLIP); - m_sprite->draw(context.color(), draw_pos, m_layer, m_flip); + MovingSprite::draw(context); context.pop_transform(); } else @@ -171,13 +170,17 @@ BadGuy::draw(DrawingContext& context) else { if (m_frozen && is_portable()) - m_freezesprite->draw(context.color(), draw_pos, m_layer); - m_sprite->draw(context.color(), draw_pos, m_layer - (m_frozen ? 1 : 0), m_flip); + m_freezesprite->draw(context.color(), get_pos(), m_layer); + + m_sprite->draw(context.color(), get_pos(), m_layer - 1, m_flip); } - if (m_glowing) + if (!m_frozen) { - m_lightsprite->draw(context.light(), m_col.m_bbox.get_middle() + draw_offset, 0); + if (m_burning) + m_burn_light_sprite->draw(context.light(), m_col.m_bbox.get_middle() + draw_offset, 0); + else if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle() + draw_offset, 0); } } } @@ -1091,7 +1094,7 @@ BadGuy::ignite() } else if (m_sprite->has_action("burning-left")) { // Burn it! - m_glowing = true; + m_burning = true; SoundManager::current()->play("sounds/fire.ogg", get_pos()); set_action("burning", m_dir, 1); set_state(STATE_BURNING); diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index 9973086c8be..48616455c8a 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -43,16 +43,16 @@ class BadGuy : public MovingSprite, public: BadGuy(const Vector& pos, const std::string& sprite_name, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", const std::string& ice_sprite_name = "images/creatures/overlays/iceoverlay/iceoverlay.sprite"); BadGuy(const Vector& pos, Direction direction, const std::string& sprite_name, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", const std::string& ice_sprite_name = "images/creatures/overlays/iceoverlay/iceoverlay.sprite"); BadGuy(const ReaderMapping& reader, const std::string& sprite_name, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", const std::string& ice_sprite_name = "images/creatures/overlays/iceoverlay/iceoverlay.sprite"); BadGuy(const ReaderMapping& reader, const std::string& sprite_name, Direction default_direction, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite", const std::string& ice_sprite_name = "images/creatures/overlays/iceoverlay/iceoverlay.sprite"); /** Called when the badguy is drawn. The default implementation @@ -287,9 +287,9 @@ class BadGuy : public MovingSprite, float m_melting_time; - SpritePtr m_lightsprite; + SpritePtr m_burn_light_sprite; SpritePtr m_freezesprite; - bool m_glowing; + bool m_burning; bool m_water_affected; Timer m_unfreeze_timer; diff --git a/src/badguy/corrupted_granito_big.cpp b/src/badguy/corrupted_granito_big.cpp index 5d98bd30f2e..1d00c3ad440 100644 --- a/src/badguy/corrupted_granito_big.cpp +++ b/src/badguy/corrupted_granito_big.cpp @@ -25,7 +25,6 @@ #include "sprite/sprite_manager.hpp" #include "supertux/sector.hpp" -static const std::string SHARD_SPRITE = "images/creatures/granito/corrupted/big/root_spike.sprite"; static const float RANGE = 5; // tiles static const float CRACK_TIME = 1.f; // seconds static const float SHAKE_TIME = 0.1f; // seconds @@ -35,8 +34,7 @@ CorruptedGranitoBig::CorruptedGranitoBig(const ReaderMapping& reader) : m_state(STATE_READY), m_crack_timer(), m_shake_timer(), - m_shake_delta(0.f), - m_rock_particles(SpriteManager::current()->create("images/particles/granito_piece.sprite")) + m_shake_delta(0.f) { parse_type(reader); @@ -91,10 +89,11 @@ CorruptedGranitoBig::kill_fall() run_dead_script(); - Sector::get().add(get_bbox().get_middle(), Vector(100.f, -500.f), SHARD_SPRITE); - Sector::get().add(get_bbox().get_middle(), Vector(270.f, -350.f), SHARD_SPRITE); - Sector::get().add(get_bbox().get_middle(), Vector(-100.f, -500.f),SHARD_SPRITE); - Sector::get().add(get_bbox().get_middle(), Vector(-270.f, -350.f),SHARD_SPRITE); + const std::string& shard_sprite = m_sprite->get_linked_sprite("shard").file; + Sector::get().add(get_bbox().get_middle(), Vector(100.f, -500.f), shard_sprite); + Sector::get().add(get_bbox().get_middle(), Vector(270.f, -350.f), shard_sprite); + Sector::get().add(get_bbox().get_middle(), Vector(-100.f, -500.f),shard_sprite); + Sector::get().add(get_bbox().get_middle(), Vector(-270.f, -350.f),shard_sprite); crack_effects(6); } @@ -165,7 +164,8 @@ CorruptedGranitoBig::crack_effects(int particles) { const Vector velocity(graphicsRandom.randf(-100, 100), graphicsRandom.randf(-400, -300)); - Sector::get().add(m_rock_particles->clone(), "piece-" + std::to_string(i), + Sector::get().add(m_sprite->create_linked_sprite("rock-particles"), + "piece-" + std::to_string(i), get_bbox().get_middle(), ANCHOR_MIDDLE, velocity, Vector(0, gravity), LAYER_OBJECTS + 3, true); diff --git a/src/badguy/corrupted_granito_big.hpp b/src/badguy/corrupted_granito_big.hpp index c1723a54fd4..2083e7bf667 100644 --- a/src/badguy/corrupted_granito_big.hpp +++ b/src/badguy/corrupted_granito_big.hpp @@ -60,8 +60,6 @@ class CorruptedGranitoBig final : public BadGuy Timer m_shake_timer; float m_shake_delta; - SpritePtr m_rock_particles; - private: CorruptedGranitoBig(const CorruptedGranitoBig&) = delete; CorruptedGranitoBig& operator=(const CorruptedGranitoBig&) = delete; diff --git a/src/badguy/crusher.cpp b/src/badguy/crusher.cpp index c0053e380cc..993d6538e91 100644 --- a/src/badguy/crusher.cpp +++ b/src/badguy/crusher.cpp @@ -65,7 +65,16 @@ Crusher::Crusher(const ReaderMapping& reader) : // TODO: Add distinct sounds for crusher hitting the ground and hitting Tux. SoundManager::current()->preload(not_ice() ? "sounds/thud.ogg" : "sounds/brick.wav"); set_state(m_state, true); - after_sprite_set(); +} + +MovingSprite::LinkedSprites +Crusher::get_linked_sprites() +{ + return { + { "left-eye", m_lefteye }, + { "right-eye", m_righteye }, + { "whites", m_whites } + }; } GameObjectTypes @@ -119,6 +128,13 @@ Crusher::on_type_change(int old_type) MovingSprite::on_type_change(old_type); } +void +Crusher::on_sprite_update() +{ + MovingSprite::on_sprite_update(); + set_state(m_state, true); +} + HitResponse Crusher::collision(GameObject& other, const CollisionHit& hit) { @@ -468,23 +484,19 @@ Crusher::spawn_roots(Direction direction) void Crusher::draw(DrawingContext& context) { - Vector draw_pos = get_pos() + m_physic.get_velocity() * context.get_time_offset(); + const Vector draw_offset = m_physic.get_velocity() * context.get_time_offset(); + const Vector draw_pos = get_pos() + draw_offset; + m_sprite->draw(context.color(), draw_pos, m_layer + 2, m_flip); - if (m_sprite->has_action("whites")) - { - // Draw crusher's eyes slightly behind. - m_lefteye->draw(context.color(), draw_pos + eye_position(false), m_layer + 1, m_flip); - m_righteye->draw(context.color(), draw_pos + eye_position(true), m_layer + 1, m_flip); - // Draw the whites of crusher's eyes even further behind. - m_whites->draw(context.color(), draw_pos, m_layer, m_flip); - } -} -void -Crusher::after_editor_set() -{ - MovingSprite::after_editor_set(); - after_sprite_set(); + // Draw crusher's eyes slightly behind. + m_lefteye->draw(context.color(), draw_pos + eye_position(false), m_layer + 1, m_flip); + m_righteye->draw(context.color(), draw_pos + eye_position(true), m_layer + 1, m_flip); + // Draw the whites of crusher's eyes even further behind. + m_whites->draw(context.color(), draw_pos, m_layer, m_flip); + + if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle() + draw_offset, m_layer + 3); } ObjectSettings @@ -580,26 +592,6 @@ Crusher::set_state(CrusherState state_, bool force) m_state = state_; } -void -Crusher::after_sprite_set() -{ - if (!m_sprite->has_action("whites")) - { - m_lefteye.reset(); - m_righteye.reset(); - m_whites.reset(); - } - else - { - m_lefteye = m_sprite->clone(); - m_lefteye->set_action("lefteye"); - m_righteye = m_sprite->clone(); - m_righteye->set_action("righteye"); - m_whites = m_sprite->clone(); - m_whites->set_action("whites"); - } -} - Vector Crusher::eye_position(bool right) const { diff --git a/src/badguy/crusher.hpp b/src/badguy/crusher.hpp index a0dd52a3c91..4911fc6ca04 100644 --- a/src/badguy/crusher.hpp +++ b/src/badguy/crusher.hpp @@ -63,9 +63,6 @@ class Crusher final : public MovingSprite virtual void update(float dt_sec) override; virtual void draw(DrawingContext& context) override; - virtual void after_editor_set() override; - virtual bool is_sideways() const { return m_sideways; } - static std::string class_name() { return "crusher"; } virtual std::string get_class_name() const override { return class_name(); } static std::string display_name() { return _("Crusher"); } @@ -78,17 +75,23 @@ class Crusher final : public MovingSprite virtual void on_flip(float height) override; + virtual bool is_sideways() const { return m_sideways; } + Physic& get_physic() { return m_physic; } bool is_big() const { return m_ic_size == LARGE; } CrusherState get_state() const { return m_state; } +protected: + LinkedSprites get_linked_sprites() override; + + void on_sprite_update() override; + private: void spawn_roots(Direction direction); bool found_victim() const; bool not_ice() const; void set_state(CrusherState state, bool force = false); - void after_sprite_set(); Vector eye_position(bool right) const; void on_type_change(int old_type) override; diff --git a/src/badguy/dive_mine.cpp b/src/badguy/dive_mine.cpp index 878ed60f518..891fc014057 100644 --- a/src/badguy/dive_mine.cpp +++ b/src/badguy/dive_mine.cpp @@ -29,18 +29,25 @@ const float DiveMine::s_max_float_acceleration = 15.f; DiveMine::DiveMine(const ReaderMapping& reader) : BadGuy(reader, "images/creatures/dive_mine/dive_mine.sprite"), - m_ticking_glow(SpriteManager::current()->create("images/creatures/dive_mine/ticking_glow/ticking_glow.sprite")), + m_ticking_glow(m_sprite->create_linked_sprite("ticking-glow")), m_chasing(true) { reset_sprites(); m_water_affected = false; } +MovingSprite::LinkedSprites +DiveMine::get_linked_sprites() +{ + return { + { "ticking-glow", m_ticking_glow } + }; +} + void DiveMine::reset_sprites() { set_action(m_dir); - m_ticking_glow->set_action("idle"); } void @@ -172,8 +179,6 @@ DiveMine::active_update(float dt_sec) } set_action("ticking", m_dir); - m_ticking_glow->set_action("ticking"); - m_physic.set_velocity(glm::normalize(dist) * s_swim_speed); } else diff --git a/src/badguy/dive_mine.hpp b/src/badguy/dive_mine.hpp index bb4c122d583..5e554e2037a 100644 --- a/src/badguy/dive_mine.hpp +++ b/src/badguy/dive_mine.hpp @@ -53,6 +53,7 @@ class DiveMine final : public BadGuy protected: virtual std::vector get_allowed_directions() const override; + LinkedSprites get_linked_sprites() override; private: void reset_sprites(); diff --git a/src/badguy/flame.cpp b/src/badguy/flame.cpp index 3a0ea80f891..d248077bfb6 100644 --- a/src/badguy/flame.cpp +++ b/src/badguy/flame.cpp @@ -31,8 +31,7 @@ static const std::string FLAME_SOUND = "sounds/flame.wav"; Flame::Flame(const ReaderMapping& reader, int type) : - BadGuy(reader, "images/creatures/flame/flame.sprite", LAYER_FLOATINGOBJECTS, - "images/objects/lightmap_light/lightmap_light-small.sprite"), + BadGuy(reader, "images/creatures/flame/flame.sprite", LAYER_FLOATINGOBJECTS), angle(0), radius(), speed(), @@ -58,23 +57,9 @@ Flame::Flame(const ReaderMapping& reader, int type) : m_start_position.y + sinf(angle) * radius)); } m_countMe = false; - m_glowing = true; SoundManager::current()->preload(FLAME_SOUND); set_colgroup_active(COLGROUP_TOUCHABLE); - - switch (m_type) - { - case FIRE: - m_lightsprite->set_color(Color(0.21f, 0.13f, 0.08f)); - break; - case GHOST: - m_lightsprite->set_color(Color(0.21f, 0.00f, 0.21f)); - break; - case ICE: - m_lightsprite->set_color(Color(0.00f, 0.13f, 0.18f)); - break; - } } GameObjectTypes @@ -179,8 +164,7 @@ Flame::freeze() SoundManager::current()->play("sounds/sizzle.ogg", get_pos()); set_action("fade", 1); - Sector::get().add("images/particles/smoke.sprite", - "default", + Sector::get().add(m_sprite->get_linked_sprite("smoke"), m_col.m_bbox.get_middle(), ANCHOR_MIDDLE, Vector(0, -150), Vector(0,0), LAYER_BACKGROUNDTILES+2); set_group(COLGROUP_DISABLED); @@ -197,8 +181,7 @@ Flame::ignite() SoundManager::current()->play("sounds/sizzle.ogg", get_pos()); set_action("fade", 1); - Sector::get().add("images/particles/smoke.sprite", - "default", + Sector::get().add(m_sprite->get_linked_sprite("smoke"), m_col.m_bbox.get_middle(), ANCHOR_MIDDLE, Vector(0, -150), Vector(0,0), LAYER_BACKGROUNDTILES+2); diff --git a/src/badguy/flyingsnowball.cpp b/src/badguy/flyingsnowball.cpp index 01ae164b0e1..bab237f0dad 100644 --- a/src/badguy/flyingsnowball.cpp +++ b/src/badguy/flyingsnowball.cpp @@ -97,10 +97,9 @@ FlyingSnowBall::active_update(float dt_sec) Vector ppos = m_col.m_bbox.get_middle(); Vector pspeed = Vector(graphicsRandom.randf(-10, 10), 150); Vector paccel = Vector(0,0); - Sector::get().add("images/particles/smoke.sprite", - "default", - ppos, ANCHOR_MIDDLE, pspeed, paccel, - LAYER_OBJECTS-1); + Sector::get().add(m_sprite->get_linked_sprite("smoke"), + ppos, ANCHOR_MIDDLE, pspeed, paccel, + LAYER_OBJECTS-1); puff_timer.start(gameRandom.randf(PUFF_INTERVAL_MIN, PUFF_INTERVAL_MAX)); } diff --git a/src/badguy/ghosttree.cpp b/src/badguy/ghosttree.cpp index c777ddaed45..b5e4c8241f4 100644 --- a/src/badguy/ghosttree.cpp +++ b/src/badguy/ghosttree.cpp @@ -45,7 +45,7 @@ GhostTree::GhostTree(const ReaderMapping& mapping) : willo_radius(200), willo_speed(1.8f), willo_color(0), - glow_sprite(SpriteManager::current()->create("images/creatures/ghosttree/ghosttree-glow.sprite")), + glow_sprite(m_sprite->create_linked_sprite("glow")), colorchange_timer(), suck_timer(), root_timer(), @@ -63,6 +63,14 @@ GhostTree::GhostTree(const ReaderMapping& mapping) : SoundManager::current()->preload("sounds/tree_suck.ogg"); } +MovingSprite::LinkedSprites +GhostTree::get_linked_sprites() +{ + return { + { "glow", glow_sprite } + }; +} + void GhostTree::die() { @@ -74,7 +82,6 @@ GhostTree::die() if (m_lives <= 0) { mystate = STATE_DYING; set_action("dying", 1); - glow_sprite->set_action("dying", 1); run_dead_script(); } } diff --git a/src/badguy/ghosttree.hpp b/src/badguy/ghosttree.hpp index cd900f1de69..161c7e215a7 100644 --- a/src/badguy/ghosttree.hpp +++ b/src/badguy/ghosttree.hpp @@ -49,6 +49,7 @@ class GhostTree final : public Boss protected: virtual std::vector get_allowed_directions() const override; + LinkedSprites get_linked_sprites() override; private: enum MyState { diff --git a/src/badguy/goldbomb.cpp b/src/badguy/goldbomb.cpp index 82eea86ed68..8298afbc7e2 100644 --- a/src/badguy/goldbomb.cpp +++ b/src/badguy/goldbomb.cpp @@ -78,8 +78,6 @@ GoldBomb::active_update(float dt_sec) // when a ledge is detected. if (m_state != GB_STATE_RECOVER) cornered(); - - return; } WalkingBadguy::active_update(dt_sec); @@ -168,7 +166,7 @@ GoldBomb::active_update(float dt_sec) m_physic.set_velocity_x(0); m_physic.set_acceleration_x(0); m_dir = vecdist.x > 0 ? Direction::RIGHT : Direction::LEFT; - m_sprite->set_action("flee", m_dir); + set_action("flee", m_dir); m_state = GB_STATE_REALIZING; m_realize_timer.start(REALIZE_TIME); break; @@ -190,7 +188,8 @@ GoldBomb::active_update(float dt_sec) } } -void GoldBomb::explode() +void +GoldBomb::explode() { MrBomb::explode(); Sector::get().add(get_pos(), !m_parent_dispenser); diff --git a/src/badguy/haywire.cpp b/src/badguy/haywire.cpp index b7c580b3dbe..d55deaaba4f 100644 --- a/src/badguy/haywire.cpp +++ b/src/badguy/haywire.cpp @@ -43,7 +43,7 @@ Haywire::Haywire(const ReaderMapping& reader) : time_until_explosion(0.0f), is_stunned(false), time_stunned(0.0f), - m_exploding_sprite(SpriteManager::current()->create("images/creatures/haywire/ticking_glow/ticking_glow.sprite")), + m_exploding_sprite(m_sprite->create_linked_sprite("ticking-glow")), m_jumping(false), m_skid_timer(), m_last_player_direction(Direction::LEFT), @@ -57,6 +57,14 @@ Haywire::Haywire(const ReaderMapping& reader) : SoundManager::current()->preload("sounds/explosion.wav"); } +MovingSprite::LinkedSprites +Haywire::get_linked_sprites() +{ + return { + { "ticking-glow", m_exploding_sprite } + }; +} + Direction Haywire::get_player_direction(const Player* player) const { @@ -168,26 +176,20 @@ Haywire::active_update(float dt_sec) // End of pathfinding. - if (stomped_timer.get_timeleft() < 0.05f) { + if (stomped_timer.get_timeleft() < 0.05f) + { if (m_jumping) - { set_action("jump", m_dir, /* loops = */ 1); - m_exploding_sprite->set_action("jump", /* loops = */ 1); - } else if (!m_skid_timer.check() && m_skid_timer.started()) - { set_action((m_last_player_direction == Direction::LEFT) ? "skid-right" : "skid-left", /* loops = */ 1); - m_exploding_sprite->set_action("skid", /* loops = */ 1); - } else - { set_action("ticking", m_last_player_direction, /* loops = */ -1); - m_exploding_sprite->set_action("run", /* loops = */ -1); - } + walk_left_action = "ticking-left"; walk_right_action = "ticking-right"; } - else { + else + { set_action("active", m_dir, /* loops = */ 1); walk_left_action = "active-left"; walk_right_action = "active-right"; diff --git a/src/badguy/haywire.hpp b/src/badguy/haywire.hpp index e0280b8db7a..2a4883aa511 100644 --- a/src/badguy/haywire.hpp +++ b/src/badguy/haywire.hpp @@ -54,6 +54,8 @@ class Haywire final : public WalkingBadguy virtual bool collision_squished(GameObject& object) override; virtual void collision_solid(const CollisionHit& hit) override; + LinkedSprites get_linked_sprites() override; + private: Direction get_player_direction(const Player* player) const; diff --git a/src/badguy/kugelblitz.cpp b/src/badguy/kugelblitz.cpp index 78d99d9ea9d..e0cebdf9b1a 100644 --- a/src/badguy/kugelblitz.cpp +++ b/src/badguy/kugelblitz.cpp @@ -42,17 +42,13 @@ Kugelblitz::Kugelblitz(const ReaderMapping& reader) : dying(), movement_timer(), lifetime(), - direction(), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light.sprite")) + direction() { m_start_position.x = m_col.m_bbox.get_left(); set_action("falling"); m_physic.enable_gravity(false); m_countMe = false; - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.2f, 0.1f, 0.0f)); - SoundManager::current()->preload("sounds/lightning.wav"); } @@ -151,8 +147,7 @@ Kugelblitz::active_update(float dt_sec) void Kugelblitz::draw(DrawingContext& context) { - m_sprite->draw(context.color(), get_pos(), m_layer); - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); + MovingSprite::draw(context); } void diff --git a/src/badguy/kugelblitz.hpp b/src/badguy/kugelblitz.hpp index 6dea704955d..0c6803ee1ff 100644 --- a/src/badguy/kugelblitz.hpp +++ b/src/badguy/kugelblitz.hpp @@ -57,7 +57,6 @@ class Kugelblitz final : public BadGuy Timer movement_timer; Timer lifetime; int direction; - SpritePtr lightsprite; private: Kugelblitz(const Kugelblitz&) = delete; diff --git a/src/badguy/livefire.cpp b/src/badguy/livefire.cpp index aabd884381c..39a52ad92ae 100644 --- a/src/badguy/livefire.cpp +++ b/src/badguy/livefire.cpp @@ -30,8 +30,6 @@ LiveFire::LiveFire(const ReaderMapping& reader) : { walk_speed = 80; set_ledge_behavior(LedgeBehavior::SMART); - m_lightsprite->set_color(Color(0.89f, 0.75f, 0.44f)); - m_glowing = true; } void @@ -122,8 +120,8 @@ LiveFire::kill_fall() Vector ppos = m_col.m_bbox.get_middle(); Vector pspeed = Vector(0, -150); Vector paccel = Vector(0,0); - Sector::get().add("images/particles/smoke.sprite", - "default", ppos, ANCHOR_MIDDLE, + Sector::get().add(m_sprite->get_linked_sprite("smoke"), + ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_BACKGROUNDTILES+2); // Extinguish the flame. @@ -131,8 +129,7 @@ LiveFire::kill_fall() m_physic.set_velocity_y(0); m_physic.set_acceleration_y(0); m_physic.enable_gravity(false); - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(Color(1.0f, 0.9f, 0.8f)); + m_light_sprite->set_color(Color(1.0f, 0.9f, 0.8f)); set_group(COLGROUP_DISABLED); state = STATE_DEAD; diff --git a/src/badguy/mrbomb.cpp b/src/badguy/mrbomb.cpp index d119aa2d2ef..a2f3a73b645 100644 --- a/src/badguy/mrbomb.cpp +++ b/src/badguy/mrbomb.cpp @@ -34,28 +34,32 @@ MrBomb::MrBomb(const ReaderMapping& reader) : WalkingBadguy(reader, "images/creatures/mr_bomb/mr_bomb.sprite", "left", "right"), m_state(MB_STATE_NORMAL), m_ticking_sound(), - m_exploding_sprite(SpriteManager::current()->create("images/creatures/mr_bomb/ticking_glow/ticking_glow.sprite")) + m_exploding_sprite(m_sprite->create_linked_sprite("ticking-glow")) { walk_speed = 80; set_ledge_behavior(LedgeBehavior::SMART); SoundManager::current()->preload("sounds/explosion.wav"); - - m_exploding_sprite->set_action("default", 1); } -MrBomb::MrBomb(const ReaderMapping& reader, const std::string& sprite, const std::string& glow_sprite): +MrBomb::MrBomb(const ReaderMapping& reader, const std::string& sprite): WalkingBadguy(reader, sprite, "left", "right"), m_state(MB_STATE_NORMAL), m_ticking_sound(), - m_exploding_sprite(SpriteManager::current()->create(glow_sprite)) + m_exploding_sprite(m_sprite->create_linked_sprite("ticking-glow")) { walk_speed = 80; set_ledge_behavior(LedgeBehavior::SMART); SoundManager::current()->preload("sounds/explosion.wav"); +} - m_exploding_sprite->set_action("default", 1); +MovingSprite::LinkedSprites +MrBomb::get_linked_sprites() +{ + return { + { "ticking-glow", m_exploding_sprite } + }; } void @@ -329,8 +333,6 @@ MrBomb::play_looping_sounds() void MrBomb::update_ticking(float dt_sec) { - m_exploding_sprite->set_action("exploding", 1); - if (on_ground()) m_physic.set_velocity_x(0); diff --git a/src/badguy/mrbomb.hpp b/src/badguy/mrbomb.hpp index 4cc07c600be..fd2af099b47 100644 --- a/src/badguy/mrbomb.hpp +++ b/src/badguy/mrbomb.hpp @@ -26,8 +26,7 @@ class MrBomb : public WalkingBadguy { public: MrBomb(const ReaderMapping& reader); - MrBomb(const ReaderMapping& reader, const std::string& sprite, - const std::string& glow_sprite = "images/creatures/mr_bomb/ticking_glow/ticking_glow.sprite"); + MrBomb(const ReaderMapping& reader, const std::string& sprite); virtual void collision_solid(const CollisionHit& hit) override; virtual HitResponse collision(GameObject& object, const CollisionHit& hit) override; @@ -65,6 +64,8 @@ class MrBomb : public WalkingBadguy virtual bool collision_squished(GameObject& object) override; + LinkedSprites get_linked_sprites() override; + protected: enum State : uint8_t { MB_STATE_NORMAL, diff --git a/src/badguy/mrtree.cpp b/src/badguy/mrtree.cpp index 8c7cf8d2bf0..f4da0716dec 100644 --- a/src/badguy/mrtree.cpp +++ b/src/badguy/mrtree.cpp @@ -123,8 +123,7 @@ MrTree::collision_squished(GameObject& object) float vy = -cosf(angle)*velocity; Vector pspeed = Vector(vx, vy); Vector paccel = Vector(0, Sector::get().get_gravity()*10); - Sector::get().add("images/particles/leaf.sprite", - "default", + Sector::get().add(m_sprite->get_linked_sprite("leaf"), ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1); diff --git a/src/badguy/root.cpp b/src/badguy/root.cpp index 2bbac27dd02..0d452ec02f6 100644 --- a/src/badguy/root.cpp +++ b/src/badguy/root.cpp @@ -124,7 +124,7 @@ Root::initialize() { const Vector velocity(graphicsRandom.randf(-100, 100), graphicsRandom.randf(-400, -300)); - Sector::get().add("images/particles/corrupted_rock.sprite", + Sector::get().add(m_sprite->create_linked_sprite("rock"), "piece-" + std::to_string(i), basepos, ANCHOR_MIDDLE, velocity, Vector(0, gravity), diff --git a/src/badguy/root.hpp b/src/badguy/root.hpp index ec727246773..6d1f90495df 100644 --- a/src/badguy/root.hpp +++ b/src/badguy/root.hpp @@ -44,6 +44,7 @@ class Root final : public BadGuy virtual bool is_freezable() const override { return false; } virtual bool is_snipable() const override { return false; } +protected: virtual std::vector get_allowed_directions() const override; private: diff --git a/src/badguy/root_sapling.cpp b/src/badguy/root_sapling.cpp index 4f58b204725..67808d967d3 100644 --- a/src/badguy/root_sapling.cpp +++ b/src/badguy/root_sapling.cpp @@ -31,8 +31,7 @@ static const float ROOT_SAPLING_RANGE = 32.f * 20; static const float ROOT_SAPLING_SPAWN_TIME = 1.35f; RootSapling::RootSapling(const ReaderMapping& reader) : - BadGuy(reader, "images/creatures/mole/corrupted/root_sapling.sprite", Direction::UP, - LAYER_TILES - 15, "images/creatures/mole/corrupted/core_glow/core_glow.sprite"), + BadGuy(reader, "images/creatures/mole/corrupted/root_sapling.sprite", Direction::UP, LAYER_TILES - 15), m_root_timer(), m_dead(false) { @@ -40,17 +39,23 @@ RootSapling::RootSapling(const ReaderMapping& reader) : set_colgroup_active(COLGROUP_MOVING); set_action("idle", m_dir); - m_glowing = true; - SoundManager::current()->preload("sounds/squish.wav"); SoundManager::current()->preload("sounds/fall.wav"); } +void +RootSapling::draw(DrawingContext& context) +{ + if (m_dead) + m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); + else + BadGuy::draw(context); +} + void RootSapling::kill_fall() { m_dead = true; - m_glowing = false; SoundManager::current()->play("sounds/fall.wav", get_pos()); @@ -76,7 +81,6 @@ bool RootSapling::collision_squished(GameObject& object) { m_dead = true; - m_glowing = false; SoundManager::current()->play("sounds/squish.wav", get_pos()); diff --git a/src/badguy/root_sapling.hpp b/src/badguy/root_sapling.hpp index 2de801170f8..e8b9bbc8e49 100644 --- a/src/badguy/root_sapling.hpp +++ b/src/badguy/root_sapling.hpp @@ -31,6 +31,7 @@ class RootSapling final : public BadGuy virtual bool collision_squished(GameObject& object) override; virtual HitResponse collision_player(Player& player, const CollisionHit& hit) override; virtual void active_update(float) override; + virtual void draw(DrawingContext& context) override; virtual bool is_flammable() const override { return false; } virtual bool is_freezable() const override { return false; } diff --git a/src/badguy/stumpy.cpp b/src/badguy/stumpy.cpp index ef3e87825aa..1a0abacdebd 100644 --- a/src/badguy/stumpy.cpp +++ b/src/badguy/stumpy.cpp @@ -112,8 +112,7 @@ Stumpy::collision_squished(GameObject& object) float vy = -cosf(angle)*velocity; Vector pspeed = Vector(vx, vy); Vector paccel = Vector(0, Sector::get().get_gravity()*10); - Sector::get().add("images/particles/bark.sprite", - "default", + Sector::get().add(m_sprite->get_linked_sprite("bark"), ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1); diff --git a/src/badguy/walking_badguy.cpp b/src/badguy/walking_badguy.cpp index 51b07ccf3fc..6448bafa2ee 100644 --- a/src/badguy/walking_badguy.cpp +++ b/src/badguy/walking_badguy.cpp @@ -25,8 +25,8 @@ WalkingBadguy::WalkingBadguy(const Vector& pos, const std::string& walk_left_action_, const std::string& walk_right_action_, int layer_, - const std::string& light_sprite_name) : - BadGuy(pos, sprite_name_, layer_, light_sprite_name), + const std::string& burn_light_sprite_name) : + BadGuy(pos, sprite_name_, layer_, burn_light_sprite_name), walk_left_action(walk_left_action_), walk_right_action(walk_right_action_), walk_speed(80), @@ -43,8 +43,8 @@ WalkingBadguy::WalkingBadguy(const Vector& pos, const std::string& walk_left_action_, const std::string& walk_right_action_, int layer_, - const std::string& light_sprite_name) : - BadGuy(pos, direction, sprite_name_, layer_, light_sprite_name), + const std::string& burn_light_sprite_name) : + BadGuy(pos, direction, sprite_name_, layer_, burn_light_sprite_name), walk_left_action(walk_left_action_), walk_right_action(walk_right_action_), walk_speed(80), @@ -60,8 +60,8 @@ WalkingBadguy::WalkingBadguy(const ReaderMapping& reader, const std::string& walk_left_action_, const std::string& walk_right_action_, int layer_, - const std::string& light_sprite_name) : - BadGuy(reader, sprite_name_, layer_, light_sprite_name), + const std::string& burn_light_sprite_name) : + BadGuy(reader, sprite_name_, layer_, burn_light_sprite_name), walk_left_action(walk_left_action_), walk_right_action(walk_right_action_), walk_speed(80), diff --git a/src/badguy/walking_badguy.hpp b/src/badguy/walking_badguy.hpp index 4e43ed62235..63353fca510 100644 --- a/src/badguy/walking_badguy.hpp +++ b/src/badguy/walking_badguy.hpp @@ -39,19 +39,19 @@ class WalkingBadguy : public BadGuy const std::string& walk_left_action, const std::string& walk_right_action, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); WalkingBadguy(const Vector& pos, Direction direction, const std::string& sprite_name, const std::string& walk_left_action, const std::string& walk_right_action, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); WalkingBadguy(const ReaderMapping& reader, const std::string& sprite_name, const std::string& walk_left_action, const std::string& walk_right_action, int layer = LAYER_OBJECTS, - const std::string& light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); + const std::string& burn_light_sprite_name = "images/objects/lightmap_light/lightmap_light-medium.sprite"); virtual GameObjectClasses get_class_types() const override { return BadGuy::get_class_types().add(typeid(WalkingBadguy)); } virtual void initialize() override; diff --git a/src/badguy/walking_candle.cpp b/src/badguy/walking_candle.cpp index ccd3167d93b..68eb7e00437 100644 --- a/src/badguy/walking_candle.cpp +++ b/src/badguy/walking_candle.cpp @@ -20,9 +20,9 @@ #include "sprite/sprite.hpp" #include "util/reader_mapping.hpp" -WalkingCandle::WalkingCandle(const ReaderMapping& reader) - : WalkingBadguy(reader, "images/creatures/mr_candle/mr-candle.sprite", "left", "right"), - m_lightcolor(1, 1, 1) +WalkingCandle::WalkingCandle(const ReaderMapping& reader) : + WalkingBadguy(reader, "images/creatures/mr_candle/mr-candle.sprite", "left", "right"), + m_lightcolor(1, 1, 1) { walk_speed = 80; max_drop_height = 64; @@ -32,10 +32,10 @@ WalkingCandle::WalkingCandle(const ReaderMapping& reader) m_lightcolor = Color(vColor); m_sprite->set_color(m_lightcolor); - m_lightsprite->set_color(m_lightcolor); + if (m_light_sprite) + m_light_sprite->set_color(m_lightcolor); m_countMe = false; - m_glowing = true; } bool @@ -54,7 +54,6 @@ void WalkingCandle::freeze() { BadGuy::freeze(); - m_glowing = false; } void @@ -63,8 +62,8 @@ WalkingCandle::unfreeze(bool melt) BadGuy::unfreeze(melt); initialize(); m_sprite->set_color(m_lightcolor); - m_lightsprite->set_color(m_lightcolor); - m_glowing = true; + if (m_light_sprite) + m_light_sprite->set_color(m_lightcolor); } HitResponse @@ -106,7 +105,8 @@ WalkingCandle::after_editor_set() WalkingBadguy::after_editor_set(); m_sprite->set_color(m_lightcolor); - m_lightsprite->set_color(m_lightcolor); + if (m_light_sprite) + m_light_sprite->set_color(m_lightcolor); } /* EOF */ diff --git a/src/badguy/willowisp.cpp b/src/badguy/willowisp.cpp index ff0933ac1e5..712880e56b0 100644 --- a/src/badguy/willowisp.cpp +++ b/src/badguy/willowisp.cpp @@ -35,8 +35,7 @@ static const float VANISH_RANGE = 512.0f; /**< Distance at which to stop trackin static const std::string SOUNDFILE = "sounds/willowisp.wav"; WillOWisp::WillOWisp(const ReaderMapping& reader) : - BadGuy(reader, "images/creatures/willowisp/willowisp.sprite", LAYER_FLOATINGOBJECTS, - "images/objects/lightmap_light/lightmap_light-small.sprite"), + BadGuy(reader, "images/creatures/willowisp/willowisp.sprite", LAYER_FLOATINGOBJECTS), PathObject(), m_mystate(STATE_IDLE), m_target_sector(), @@ -79,11 +78,13 @@ WillOWisp::WillOWisp(const ReaderMapping& reader) : SoundManager::current()->preload(SOUNDFILE); SoundManager::current()->preload("sounds/warp.wav"); - m_lightsprite->set_color(Color(m_color.red * 0.2f, - m_color.green * 0.2f, - m_color.blue * 0.2f)); + if (m_light_sprite) + { + m_light_sprite->set_color(Color(m_color.red * 0.2f, + m_color.green * 0.2f, + m_color.blue * 0.2f)); + } m_sprite->set_color(m_color); - m_glowing = true; set_action("idle"); } @@ -101,9 +102,12 @@ WillOWisp::after_editor_set() { BadGuy::after_editor_set(); - m_lightsprite->set_color(Color(m_color.red * 0.2f, - m_color.green * 0.2f, - m_color.blue * 0.2f)); + if (m_light_sprite) + { + m_light_sprite->set_color(Color(m_color.red * 0.2f, + m_color.green * 0.2f, + m_color.blue * 0.2f)); + } m_sprite->set_color(m_color); } diff --git a/src/object/bigsnowball.cpp b/src/object/bigsnowball.cpp index 3f8239b8ebf..ad1c79c1493 100644 --- a/src/object/bigsnowball.cpp +++ b/src/object/bigsnowball.cpp @@ -211,7 +211,7 @@ BigSnowball::spawn_particles() { for (int i = 0; i < 8; i++) { - Sector::get().add(m_sprite_name, "particle", + Sector::get().add(m_sprite->get_linked_sprite("particle"), get_bbox().get_middle() + (15.f * Vector(std::cos(math::PI_4*static_cast(i)), std::sin(math::PI_4*static_cast(i)))), ANCHOR_MIDDLE, (150.f * (glm::normalize(Vector(std::cos(math::PI_4*static_cast(i)), std::sin(math::PI_4*static_cast(i)))))) + Vector(gameRandom.randf(-40.f, 40.f), gameRandom.randf(-40.f, 40.f)), diff --git a/src/object/block.cpp b/src/object/block.cpp index a51e65f4906..39ca94c7078 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -186,14 +186,17 @@ Block::break_me() const auto gravity = Sector::get().get_gravity() * 100; Vector pos = get_pos() + Vector(16.0f, 16.0f); - for (const char* action : {"piece1", "piece2", "piece3", "piece4", "piece5", "piece6"}) + if (m_sprite->has_linked_sprite("break-particles")) { - Vector velocity(graphicsRandom.randf(-100, 100), - graphicsRandom.randf(-400, -300)); - Sector::get().add(m_sprite->clone(), action, - pos, ANCHOR_MIDDLE, - velocity, Vector(0, gravity), - m_layer); + for (const char* action : {"piece1", "piece2", "piece3", "piece4", "piece5", "piece6"}) + { + Vector velocity(graphicsRandom.randf(-100, 100), + graphicsRandom.randf(-400, -300)); + Sector::get().add(m_sprite->create_linked_sprite("break-particles"), action, + pos, ANCHOR_MIDDLE, + velocity, Vector(0, gravity), + m_layer); + } } remove_me(); diff --git a/src/object/bonus_block.cpp b/src/object/bonus_block.cpp index 6b8834572df..2d87645f87f 100644 --- a/src/object/bonus_block.cpp +++ b/src/object/bonus_block.cpp @@ -44,7 +44,6 @@ #include "util/reader_mapping.hpp" #include "util/writer.hpp" #include "video/drawing_context.hpp" -#include "video/surface.hpp" namespace { @@ -139,7 +138,7 @@ BonusBlock::BonusBlock(const ReaderMapping& mapping) : if (m_contents == Content::LIGHT || m_contents == Content::LIGHT_ON) { SoundManager::current()->preload("sounds/switch.ogg"); - m_lightsprite = Surface::from_file("/images/objects/lightmap_light/bonusblock_light.png"); + m_lightsprite = m_sprite->create_linked_sprite("on-light"); if (m_contents == Content::LIGHT_ON) set_action("on"); else @@ -165,6 +164,18 @@ BonusBlock::set_object(std::unique_ptr object) m_objects.push_back(std::move(object)); } +MovingSprite::LinkedSprites +BonusBlock::get_linked_sprites() +{ + if (m_contents == Content::LIGHT || m_contents == Content::LIGHT_ON) + { + return { + { "on-light", m_lightsprite } + }; + } + return {}; +} + GameObjectTypes BonusBlock::get_types() const { @@ -395,7 +406,7 @@ BonusBlock::try_open(Player* player) case Content::RETROSTAR: { Sector::get().add(get_pos() + Vector(0, -32), direction, - "images/powerups/retro/golden_herring.png"); + "images/powerups/retro/golden_herring.sprite"); play_upgrade_sound = true; break; } @@ -561,7 +572,7 @@ BonusBlock::try_drop(Player *player) case Content::RETROSTAR: { Sector::get().add(get_pos() + Vector(0, 32), direction, - "images/powerups/retro/golden_herring.png"); + "images/powerups/retro/golden_herring.sprite"); play_upgrade_sound = true; countdown = true; break; @@ -688,7 +699,7 @@ BonusBlock::draw(DrawingContext& context) { Vector pos = get_pos() + (m_col.m_bbox.get_size().as_vector() - Vector(static_cast(m_lightsprite->get_width()), static_cast(m_lightsprite->get_height()))) / 2.0f; - context.light().draw_surface(m_lightsprite, pos, 10); + m_lightsprite->draw(context.light(), pos, 10); } } @@ -748,7 +759,7 @@ BonusBlock::preload_contents(int d) case 6: // Light. case 15: // Light (On). SoundManager::current()->preload("sounds/switch.ogg"); - m_lightsprite=Surface::from_file("/images/objects/lightmap_light/bonusblock_light.png"); + m_lightsprite = m_sprite->create_linked_sprite("on-light"); break; case 7: diff --git a/src/object/bonus_block.hpp b/src/object/bonus_block.hpp index 924f59bc0ad..d6a6f4a3178 100644 --- a/src/object/bonus_block.hpp +++ b/src/object/bonus_block.hpp @@ -72,6 +72,9 @@ class BonusBlock final : public Block void try_open(Player* player); +protected: + LinkedSprites get_linked_sprites() override; + private: void add_object(std::unique_ptr object); void set_object(std::unique_ptr object); @@ -111,7 +114,7 @@ class BonusBlock final : public Block int m_hit_counter; std::string m_script; - SurfacePtr m_lightsprite; + SpritePtr m_lightsprite; std::string m_coin_sprite; private: diff --git a/src/object/bullet.cpp b/src/object/bullet.cpp index 64d495242ec..cbe9ed3174e 100644 --- a/src/object/bullet.cpp +++ b/src/object/bullet.cpp @@ -30,7 +30,7 @@ Bullet::Bullet(const Vector& pos, const Vector& xm, Direction dir, BonusType typ physic(), life_count(3), sprite(), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")), + lightsprite(), type(type_) { physic.set_velocity(xm); @@ -38,8 +38,6 @@ Bullet::Bullet(const Vector& pos, const Vector& xm, Direction dir, BonusType typ switch (type) { case BONUS_FIRE: sprite = SpriteManager::current()->create("images/objects/bullets/firebullet.sprite"); - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.3f, 0.1f, 0.0f)); break; case BONUS_ICE: @@ -53,6 +51,8 @@ Bullet::Bullet(const Vector& pos, const Vector& xm, Direction dir, BonusType typ break; } + lightsprite = sprite->create_linked_light_sprite(); + m_col.m_bbox.set_pos(pos); m_col.m_bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height()); } @@ -61,12 +61,19 @@ void Bullet::update(float dt_sec) { // Cause fireball color to flicker randomly. - if (graphicsRandom.rand(5) != 0) { - lightsprite->set_color(Color(0.3f + graphicsRandom.randf(10) / 100.0f, - 0.1f + graphicsRandom.randf(20.0f) / 100.0f, - graphicsRandom.randf(10.0f) / 100.0f)); - } else - lightsprite->set_color(Color(0.3f, 0.1f, 0.0f)); + if (lightsprite) + { + if (graphicsRandom.rand(5) != 0) + { + lightsprite->set_color(Color(0.3f + graphicsRandom.randf(10) / 100.0f, + 0.1f + graphicsRandom.randf(20.0f) / 100.0f, + graphicsRandom.randf(10.0f) / 100.0f)); + } + else + { + lightsprite->set_color(Color(0.3f, 0.1f, 0.0f)); + } + } if (life_count <= 0) { @@ -94,9 +101,8 @@ void Bullet::draw(DrawingContext& context) { sprite->draw(context.color(), get_pos(), LAYER_OBJECTS); - if (type == BONUS_FIRE){ + if (lightsprite) lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); - } } void diff --git a/src/object/candle.cpp b/src/object/candle.cpp index ad605007d03..dbecd803fec 100644 --- a/src/object/candle.cpp +++ b/src/object/candle.cpp @@ -22,7 +22,6 @@ #include "math/random.hpp" #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/flip_level_transformer.hpp" #include "supertux/sector.hpp" #include "util/reader_mapping.hpp" @@ -32,28 +31,59 @@ Candle::Candle(const ReaderMapping& mapping) : burning(true), flicker(true), lightcolor(1.0f, 1.0f, 1.0f), - candle_light_1(SpriteManager::current()->create("images/objects/candle/candle-light-1.sprite")), - candle_light_2(SpriteManager::current()->create("images/objects/candle/candle-light-2.sprite")) + candle_light_1(m_sprite->create_linked_sprite("light-1")), + candle_light_2(m_sprite->create_linked_sprite("light-2")) { mapping.get("burning", burning, true); mapping.get("flicker", flicker, true); - std::vector vColor; - if (!mapping.get("color", vColor)) vColor = {1.0f, 1.0f, 1.0f}; mapping.get("layer", m_layer); // Backwards compatibility + std::vector vColor; + if (!mapping.get("color", vColor)) vColor = {1.f, 1.f, 1.f}; + + //std::cout << vColor[0] << vColor[1] << vColor[2] << vColor[3] << std::endl; + lightcolor = Color(vColor); + + candle_light_1->set_blend(Blend::ADD); + candle_light_2->set_blend(Blend::ADD); + // Change the light color if defined. - if (vColor.size() >= 3) { - lightcolor = Color(vColor); - candle_light_1->set_blend(Blend::ADD); - candle_light_2->set_blend(Blend::ADD); + if (lightcolor.greyscale() < 1.f) + { candle_light_1->set_color(lightcolor); candle_light_2->set_color(lightcolor); - // The following allows the original candle appearance to be preserved. - candle_light_1->set_action("white"); - candle_light_2->set_action("white"); + + set_action(burning ? "on-white" : "off-white"); } + else + { + set_action(burning ? "on" : "off"); + } +} - set_action(burning ? "on" : "off"); +MovingSprite::LinkedSprites +Candle::get_linked_sprites() +{ + return { + { "light-1", candle_light_1 }, + { "light-2", candle_light_2 } + }; +} + +void +Candle::on_sprite_update() +{ + MovingSprite::on_sprite_update(); + + candle_light_1->set_blend(Blend::ADD); + candle_light_2->set_blend(Blend::ADD); + + // Change the light color if defined. + if (lightcolor.greyscale() < 1.f) + { + candle_light_1->set_color(lightcolor); + candle_light_2->set_color(lightcolor); + } } void @@ -61,10 +91,11 @@ Candle::after_editor_set() { MovingSprite::after_editor_set(); - candle_light_1->set_color(lightcolor); - candle_light_2->set_color(lightcolor); - - set_action(burning ? "on" : "off"); + // Change the light color if defined. + if (lightcolor.greyscale() < 1.f) + set_action(burning ? "on-white" : "off-white"); + else + set_action(burning ? "on" : "off"); } ObjectSettings @@ -113,8 +144,7 @@ Candle::puff_smoke() Vector ppos = m_col.m_bbox.get_middle(); Vector pspeed = Vector(0, -150); Vector paccel = Vector(0,0); - Sector::get().add("images/particles/smoke.sprite", - "default", + Sector::get().add(m_sprite->get_linked_sprite("smoke"), ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_BACKGROUNDTILES+2); @@ -131,11 +161,11 @@ Candle::set_burning(bool burning_) { if (burning == burning_) return; burning = burning_; - if (burning_) { - set_action("on"); - } else { - set_action("off"); - } + if (lightcolor.greyscale() < 1.f) + set_action(burning_ ? "on-white" : "off-white"); + else + set_action(burning_ ? "on" : "off"); + // Puff smoke for flickering light sources only. if (flicker) puff_smoke(); } diff --git a/src/object/candle.hpp b/src/object/candle.hpp index 71fff88c190..7589e3d11c6 100644 --- a/src/object/candle.hpp +++ b/src/object/candle.hpp @@ -45,6 +45,7 @@ class Candle final : public MovingSprite virtual GameObjectClasses get_class_types() const override { return MovingSprite::get_class_types().add(typeid(Candle)); } virtual ObjectSettings get_settings() override; + virtual LinkedSprites get_linked_sprites() override; virtual void after_editor_set() override; virtual void on_flip(float height) override; @@ -66,6 +67,9 @@ class Candle final : public MovingSprite */ void set_burning(bool burning); +protected: + void on_sprite_update() override; + private: /** * @scripting diff --git a/src/object/explosion.cpp b/src/object/explosion.cpp index 1e93485596c..498c898ab47 100644 --- a/src/object/explosion.cpp +++ b/src/object/explosion.cpp @@ -28,49 +28,42 @@ #include "object/weak_block.hpp" #include "supertux/sector.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/sector.hpp" -Explosion::Explosion(const Vector& pos, float p_push_strength, - int p_num_particles, bool p_short_fuse) : - MovingSprite(pos, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS + 40, COLGROUP_MOVING), +Explosion::Explosion(const Vector& pos, float p_push_strength, int p_num_particles, bool p_short_fuse) : + MovingSprite(pos, p_short_fuse ? "images/objects/explosion/explosion_medium.sprite" : "images/objects/explosion/explosion_large.sprite", + LAYER_OBJECTS + 40, COLGROUP_MOVING), hurt(!p_short_fuse), push_strength(p_push_strength), num_particles(p_num_particles), m_state(E_STATE_WAITING), - m_lightsprite(SpriteManager::current()->create(p_short_fuse ? - "images/objects/lightmap_light/lightmap_light-medium.sprite" : - "images/objects/lightmap_light/lightmap_light-large.sprite")), - m_color(1.f, 0.5f, 0.2f, 0.f), m_fading_timer(), short_fuse(p_short_fuse) { set_pos(get_pos() - (m_col.m_bbox.get_middle() - get_pos())); SoundManager::current()->preload(short_fuse ? "sounds/firecracker.ogg" : "sounds/explosion.wav"); - - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(m_color); } Explosion::Explosion(const ReaderMapping& reader) : - MovingSprite(reader, "images/objects/explosion/explosion.sprite", LAYER_OBJECTS + 40, COLGROUP_MOVING), + MovingSprite(reader, "images/objects/explosion/explosion_large.sprite", + LAYER_OBJECTS + 40, COLGROUP_MOVING), hurt(true), push_strength(-1), num_particles(100), m_state(E_STATE_WAITING), - m_lightsprite(nullptr), - m_color(1.f, 0.5f, 0.2f, 0.f), m_fading_timer(), short_fuse(false) { - SoundManager::current()->preload(short_fuse ? "sounds/firecracker.ogg" : "sounds/explosion.wav"); + SoundManager::current()->preload("sounds/explosion.wav"); +} - m_lightsprite = (SpriteManager::current()->create(short_fuse ? - "images/objects/lightmap_light/lightmap_light-medium.sprite" : - "images/objects/lightmap_light/lightmap_light-large.sprite")); - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(m_color); +void +Explosion::on_sprite_update() +{ + MovingSprite::on_sprite_update(); + if (m_light_sprite) + m_light_sprite->get_color().alpha = 0.f; } void @@ -171,7 +164,8 @@ Explosion::update(float ) break; case E_STATE_EXPLODING: - m_color.alpha = std::min(m_fading_timer.get_progress(), 1.f); + if (m_light_sprite) + m_light_sprite->get_color().alpha = std::min(m_fading_timer.get_progress(), 1.f); if (m_fading_timer.check()) { @@ -182,7 +176,8 @@ Explosion::update(float ) break; case E_STATE_FADING: - m_color.alpha = std::max(1.f - m_fading_timer.get_progress(), 0.f); + if (m_light_sprite) + m_light_sprite->get_color().alpha = std::max(1.f - m_fading_timer.get_progress(), 0.f); if (m_fading_timer.check()) { @@ -193,14 +188,6 @@ Explosion::update(float ) } } -void -Explosion::draw(DrawingContext& context) -{ - m_sprite->draw(context.color(), get_pos(), LAYER_OBJECTS+40); - m_lightsprite->set_color(m_color); - m_lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); -} - HitResponse Explosion::collision(GameObject& other, const CollisionHit& ) { diff --git a/src/object/explosion.hpp b/src/object/explosion.hpp index ecdabf9c5ce..c31fb41a489 100644 --- a/src/object/explosion.hpp +++ b/src/object/explosion.hpp @@ -39,13 +39,15 @@ class Explosion final : public MovingSprite virtual GameObjectClasses get_class_types() const override { return MovingSprite::get_class_types().add(typeid(Explosion)); } virtual void update(float dt_sec) override; - virtual void draw(DrawingContext& context) override; virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override; virtual bool is_saveable() const override { return false; } bool hurts() const { return hurt; } void hurts (bool val) { hurt = val; } +protected: + void on_sprite_update() override; + private: /** plays sound, starts animation */ void explode(); @@ -62,10 +64,8 @@ class Explosion final : public MovingSprite float push_strength; int num_particles; State m_state; - SpritePtr m_lightsprite; - Color m_color; Timer m_fading_timer; - bool short_fuse; + const bool short_fuse; private: Explosion(const Explosion&) = delete; diff --git a/src/object/firefly.cpp b/src/object/firefly.cpp index 37b473d7a66..2d7d976f88e 100644 --- a/src/object/firefly.cpp +++ b/src/object/firefly.cpp @@ -24,27 +24,16 @@ #include "object/player.hpp" #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/flip_level_transformer.hpp" #include "supertux/game_session.hpp" #include "supertux/sector.hpp" #include "util/reader_mapping.hpp" -static const Color TORCH_LIGHT_COLOR = Color(0.87f, 0.64f, 0.12f); /** Color of the light specific to the torch firefly sprite. */ -static const Vector TORCH_LIGHT_OFFSET = Vector(0, 12); /** Offset of the light specific to the torch firefly sprite. */ - Firefly::Firefly(const ReaderMapping& mapping) : - MovingSprite(mapping, "images/objects/resetpoints/default-resetpoint.sprite", LAYER_TILES, COLGROUP_TOUCHABLE), - m_sprite_light(), - activated(false), - initial_position(get_pos()) + MovingSprite(mapping, "images/objects/resetpoints/default-resetpoint.sprite", LAYER_TILES, COLGROUP_TOUCHABLE), + activated(false), + initial_position(get_pos()) { - if (m_sprite_name.find("torch", 0) != std::string::npos) { - m_sprite_light = SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite"); - m_sprite_light->set_blend(Blend::ADD); - m_sprite_light->set_color(TORCH_LIGHT_COLOR); - } - update_state(); // Load sound. @@ -62,12 +51,10 @@ Firefly::Firefly(const ReaderMapping& mapping) : void Firefly::draw(DrawingContext& context) { - MovingSprite::draw(context); + m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); - if (m_sprite_name.find("torch", 0) != std::string::npos && (activated || - m_sprite->get_action() == "ringing")) { - m_sprite_light->draw(context.light(), m_col.m_bbox.get_middle() + (m_flip == NO_FLIP ? -TORCH_LIGHT_OFFSET : TORCH_LIGHT_OFFSET), 0); - } + if (m_light_sprite && (activated || m_sprite->get_action() == "ringing")) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle(), 0, m_flip); } void @@ -116,7 +103,7 @@ Firefly::collision(GameObject& other, const CollisionHit& ) float vy = -cosf(angle)*velocity; Vector pspeed = Vector(vx, vy); Vector paccel = Vector(0.0f, 1000.0f); - Sector::get().add("images/particles/reset.sprite", "default", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1); + Sector::get().add(m_sprite->get_linked_sprite("reset"), ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1); } if ( m_sprite_name.find("vbell", 0) != std::string::npos ) { diff --git a/src/object/firefly.hpp b/src/object/firefly.hpp index 55c820d6a1e..b266a395f91 100644 --- a/src/object/firefly.hpp +++ b/src/object/firefly.hpp @@ -46,7 +46,6 @@ class Firefly final : public MovingSprite void update_state(); private: - SpritePtr m_sprite_light; bool activated; Vector initial_position; /**< position as in level file. This is where Tux will have to respawn, as the level is reset every time */ diff --git a/src/object/flower.cpp b/src/object/flower.cpp index c34212766f1..dc638eb2111 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -26,34 +26,32 @@ Flower::Flower(BonusType _type, const std::string& custom_sprite) : type(_type), sprite(), flip(NO_FLIP), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + lightsprite() { m_col.m_bbox.set_size(32, 32); - lightsprite->set_blend(Blend::ADD); if (type == BONUS_FIRE) { sprite = SpriteManager::current()->create(custom_sprite.empty() ? "images/powerups/fireflower/fireflower.sprite" : custom_sprite); SoundManager::current()->preload("sounds/fire-flower.wav"); - lightsprite->set_color(Color(0.3f, 0.0f, 0.0f)); } else if (type == BONUS_ICE) { sprite = SpriteManager::current()->create(custom_sprite.empty() ? "images/powerups/iceflower/iceflower.sprite" : custom_sprite); SoundManager::current()->preload("sounds/fire-flower.wav"); - lightsprite->set_color(Color(0.0f, 0.1f, 0.2f)); } else if (type == BONUS_AIR) { sprite = SpriteManager::current()->create(custom_sprite.empty() ? "images/powerups/airflower/airflower.sprite" : custom_sprite); SoundManager::current()->preload("sounds/fire-flower.wav"); - lightsprite->set_color(Color(0.15f, 0.0f, 0.15f)); } else if (type == BONUS_EARTH) { sprite = SpriteManager::current()->create(custom_sprite.empty() ? "images/powerups/earthflower/earthflower.sprite" : custom_sprite); SoundManager::current()->preload("sounds/fire-flower.wav"); - lightsprite->set_color(Color(0.0f, 0.3f, 0.0f)); - } else { + } + else { assert(false); } + lightsprite = sprite->create_linked_light_sprite(); + set_group(COLGROUP_TOUCHABLE); } @@ -66,7 +64,8 @@ void Flower::draw(DrawingContext& context) { sprite->draw(context.color(), get_pos(), LAYER_OBJECTS, flip); - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); + if (lightsprite) + lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); } HitResponse diff --git a/src/object/growup.cpp b/src/object/growup.cpp index 297089dfaf3..74d0d78eae1 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -22,23 +22,27 @@ #include "math/util.hpp" #include "object/player.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" GrowUp::GrowUp(const Vector& pos, Direction direction, const std::string& custom_sprite) : MovingSprite(pos, custom_sprite.empty() ? "images/powerups/egg/egg.sprite" : custom_sprite, LAYER_OBJECTS, COLGROUP_MOVING), m_physic(), m_custom_sprite(!custom_sprite.empty()), - m_shadesprite(SpriteManager::current()->create("images/powerups/egg/egg.sprite")), - m_lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + m_shadesprite(m_sprite->create_linked_sprite("shade")) { m_physic.enable_gravity(true); m_physic.set_velocity_x((direction == Direction::LEFT) ? -100.0f : 100.0f); SoundManager::current()->preload("sounds/grow.ogg"); + // Set the shadow action for the egg sprite, so it remains in place as the egg rolls. m_shadesprite->set_action("shadow"); - // Configure the light sprite for the glow effect. - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(Color(0.2f, 0.2f, 0.0f)); +} + +MovingSprite::LinkedSprites +GrowUp::get_linked_sprites() +{ + return { + { "shade", m_shadesprite } + }; } void @@ -59,7 +63,6 @@ GrowUp::draw(DrawingContext& context) return; m_shadesprite->draw(context.color(), get_pos(), m_layer); - m_lightsprite->draw(context.light(), get_bbox().get_middle(), 0); } void diff --git a/src/object/growup.hpp b/src/object/growup.hpp index 3f0d4a88864..cc9802c0ca3 100644 --- a/src/object/growup.hpp +++ b/src/object/growup.hpp @@ -37,12 +37,14 @@ class GrowUp final : public MovingSprite void do_jump(); +protected: + LinkedSprites get_linked_sprites() override; + private: Physic m_physic; const bool m_custom_sprite; SpritePtr m_shadesprite; - SpritePtr m_lightsprite; private: GrowUp(const GrowUp&) = delete; diff --git a/src/object/key.cpp b/src/object/key.cpp index 2e8f2e47035..abc2183fb71 100644 --- a/src/object/key.cpp +++ b/src/object/key.cpp @@ -22,7 +22,6 @@ #include "object/player.hpp" #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/sector.hpp" #include "trigger/door.hpp" #include "util/reader_mapping.hpp" @@ -39,7 +38,6 @@ Key::Key(const ReaderMapping& reader) : m_my_door_pos(0.f, 0.f), m_color(Color::WHITE), m_owner(), - m_lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")), m_total_time_elapsed(), m_target_speed() { @@ -47,8 +45,8 @@ Key::Key(const ReaderMapping& reader) : if (reader.get("color", vColor)) { m_color = Color(vColor); } - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(m_color); + if (m_light_sprite) + m_light_sprite->set_color(m_color); // TODO: Add proper sound SoundManager::current()->preload("sounds/metal_hit.ogg"); @@ -74,7 +72,7 @@ Key::update(float dt_sec) if (spawn_particle_now) { Sector::get().add( - "images/particles/sparkle.sprite", "small", + m_sprite->get_linked_sprite("sparkle-small"), ppos, ANCHOR_MIDDLE, Vector(0, 0), Vector(0, 0), LAYER_OBJECTS + 6, false, m_color); } @@ -181,7 +179,9 @@ void Key::draw(DrawingContext& context) { m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); - m_lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), m_layer+1); + + if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle(), m_layer + 1); } ObjectSettings @@ -201,8 +201,8 @@ Key::after_editor_set() { MovingSprite::after_editor_set(); - m_lightsprite->set_blend(Blend::ADD); - m_lightsprite->set_color(m_color); + if (m_light_sprite) + m_light_sprite->set_color(m_color); m_sprite->set_color(m_color); } @@ -219,7 +219,7 @@ Key::spawn_use_particles() for (int i = 1; i < 9; i++) { Vector direction = glm::normalize(Vector(std::cos(float(i) * math::PI_4), std::sin(float(i) * math::PI_4))); - Sector::get().add("images/particles/sparkle.sprite", "small-key-collect", + Sector::get().add(m_sprite->get_linked_sprite("sparkle-collect"), get_bbox().get_middle(), ANCHOR_MIDDLE, Vector(400.f * direction), -Vector(400.f * direction) * 2.8f, LAYER_OBJECTS + 6, false, m_color); } diff --git a/src/object/key.hpp b/src/object/key.hpp index 81097fe9999..5defb7ea835 100644 --- a/src/object/key.hpp +++ b/src/object/key.hpp @@ -63,7 +63,6 @@ class Key final : public MovingSprite Vector m_my_door_pos; Color m_color; Player* m_owner; - SpritePtr m_lightsprite; float m_total_time_elapsed; float m_target_speed; diff --git a/src/object/lantern.cpp b/src/object/lantern.cpp index 9b979d0602e..0a2cac50679 100644 --- a/src/object/lantern.cpp +++ b/src/object/lantern.cpp @@ -23,13 +23,11 @@ #include "badguy/willowisp.hpp" #include "editor/editor.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "util/reader_mapping.hpp" Lantern::Lantern(const ReaderMapping& reader) : Rock(reader, "images/objects/lantern/lantern.sprite"), - lightcolor(1.0f, 1.0f, 1.0f), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light.sprite")) + lightcolor(1.0f, 1.0f, 1.0f) { std::vector vColor; if (reader.get("color", vColor)) { @@ -39,17 +37,14 @@ Lantern::Lantern(const ReaderMapping& reader) : lightcolor = Color(1, 1, 1); } } - lightsprite->set_blend(Blend::ADD); updateColor(); SoundManager::current()->preload("sounds/willocatch.wav"); } Lantern::Lantern(const Vector& pos) : Rock(pos, "images/objects/lantern/lantern.sprite"), - lightcolor(0.0f, 0.0f, 0.0f), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light.sprite")) + lightcolor(0.0f, 0.0f, 0.0f) { - lightsprite->set_blend(Blend::ADD); updateColor(); SoundManager::current()->preload("sounds/willocatch.wav"); } @@ -75,8 +70,10 @@ Lantern::after_editor_set() } void -Lantern::updateColor(){ - lightsprite->set_color(lightcolor); +Lantern::updateColor() +{ + if (m_light_sprite) + m_light_sprite->set_color(lightcolor); //Turn lantern off if light is black if (lightcolor.red == 0 && lightcolor.green == 0 && lightcolor.blue == 0){ set_action("off"); @@ -88,15 +85,17 @@ Lantern::updateColor(){ } void -Lantern::draw(DrawingContext& context){ +Lantern::draw(DrawingContext& context +){ //Draw the Sprite. MovingSprite::draw(context); //Let there be light. - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); + if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); } -HitResponse Lantern::collision(GameObject& other, const CollisionHit& hit) { - +HitResponse Lantern::collision(GameObject& other, const CollisionHit& hit) +{ WillOWisp* wow = dynamic_cast(&other); if (wow && (is_open() || wow->get_color().greyscale() == 0.f)) { @@ -128,7 +127,6 @@ Lantern::grab(MovingObject& object, const Vector& pos, Direction dir) if (is_open()) { set_action("off-open"); } - } void diff --git a/src/object/lantern.hpp b/src/object/lantern.hpp index 435a1feaa02..8807cc89886 100644 --- a/src/object/lantern.hpp +++ b/src/object/lantern.hpp @@ -51,10 +51,11 @@ class Lantern final : public Rock void add_color(const Color& c); private: - Color lightcolor; - SpritePtr lightsprite; void updateColor(); +private: + Color lightcolor; + private: Lantern(const Lantern&) = delete; Lantern& operator=(const Lantern&) = delete; diff --git a/src/object/lit_object.cpp b/src/object/lit_object.cpp index b9c7c1ed029..8c438295642 100644 --- a/src/object/lit_object.cpp +++ b/src/object/lit_object.cpp @@ -29,8 +29,7 @@ LitObject::LitObject(const ReaderMapping& reader) : m_light_offset(-6.f, -17.f), m_light_sprite_name("images/objects/lightflower/light/glow_light.sprite"), m_sprite_action("default"), - m_light_sprite_action("default"), - m_light_sprite() + m_light_sprite_action("default") { reader.get("light-offset-x", m_light_offset.x); reader.get("light-offset-y", m_light_offset.y); diff --git a/src/object/lit_object.hpp b/src/object/lit_object.hpp index 641ce1d6172..518df3046a4 100644 --- a/src/object/lit_object.hpp +++ b/src/object/lit_object.hpp @@ -69,7 +69,6 @@ class LitObject final : public MovingSprite std::string m_light_sprite_name; std::string m_sprite_action; std::string m_light_sprite_action; - SpritePtr m_light_sprite; #ifdef DOXYGEN_SCRIPTING /** diff --git a/src/object/moving_sprite.cpp b/src/object/moving_sprite.cpp index e71205bb0c9..0bb453caa87 100644 --- a/src/object/moving_sprite.cpp +++ b/src/object/moving_sprite.cpp @@ -34,14 +34,16 @@ MovingSprite::MovingSprite(const Vector& pos, const std::string& sprite_name_, int layer_, CollisionGroup collision_group) : m_sprite_name(sprite_name_), m_default_sprite_name(sprite_name_), - m_sprite(SpriteManager::current()->create(m_sprite_name)), + m_sprite(), + m_light_sprite(), m_layer(layer_), m_flip(NO_FLIP), m_sprite_found(false), m_custom_layer(false) { + change_sprite(m_sprite_name); + m_col.m_bbox.set_pos(pos); - update_hitbox(); set_group(collision_group); } @@ -56,13 +58,12 @@ MovingSprite::MovingSprite(const ReaderMapping& reader, const std::string& sprit m_sprite_name(sprite_name_), m_default_sprite_name(sprite_name_), m_sprite(), + m_light_sprite(), m_layer(layer_), m_flip(NO_FLIP), m_sprite_found(false), m_custom_layer(reader.get("z-pos", m_layer)) { - reader.get("x", m_col.m_bbox.get_left()); - reader.get("y", m_col.m_bbox.get_top()); m_sprite_found = reader.get("sprite", m_sprite_name); //Make the sprite go default when the sprite file is invalid or sprite change fails @@ -80,18 +81,17 @@ MovingSprite::MovingSprite(const ReaderMapping& reader, int layer_, CollisionGro m_sprite_name(), m_default_sprite_name(), m_sprite(), + m_light_sprite(), m_layer(layer_), m_flip(NO_FLIP), m_sprite_found(false), m_custom_layer(reader.get("z-pos", m_layer)) { - reader.get("x", m_col.m_bbox.get_left()); - reader.get("y", m_col.m_bbox.get_top()); m_sprite_found = reader.get("sprite", m_sprite_name); - //m_default_sprite_name = m_sprite_name; - m_sprite = SpriteManager::current()->create(m_sprite_name); - update_hitbox(); + if (m_sprite_name.empty() || !change_sprite(m_sprite_name)) + m_sprite_found = false; + set_group(collision_group); } @@ -99,6 +99,9 @@ void MovingSprite::draw(DrawingContext& context) { m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); + + if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); } void @@ -145,8 +148,8 @@ MovingSprite::update_hitbox() void MovingSprite::set_action(const std::string& name) { - m_sprite->set_action(name); - update_hitbox(); + if (m_sprite->set_action(name)) + on_sprite_update(); } void @@ -158,37 +161,39 @@ MovingSprite::set_action_loops(const std::string& name, int loops) void MovingSprite::set_action(const std::string& name, int loops) { - m_sprite->set_action(name, loops); - update_hitbox(); + if (m_sprite->set_action(name, loops)) + on_sprite_update(); } void MovingSprite::set_action(const std::string& name, const Direction& dir, int loops) { - m_sprite->set_action(name, dir, loops); - update_hitbox(); + if (m_sprite->set_action(name, dir, loops)) + on_sprite_update(); } void MovingSprite::set_action(const Direction& dir, const std::string& name, int loops) { - m_sprite->set_action(dir, name, loops); - update_hitbox(); + if (m_sprite->set_action(dir, name, loops)) + on_sprite_update(); } void MovingSprite::set_action(const Direction& dir, int loops) { - m_sprite->set_action(dir, loops); - update_hitbox(); + if (m_sprite->set_action(dir, loops)) + on_sprite_update(); } void MovingSprite::set_action_centered(const std::string& action, int loops) { Vector old_size = m_col.m_bbox.get_size().as_vector(); - m_sprite->set_action(action, loops); - update_hitbox(); + if (!m_sprite->set_action(action, loops)) + return; + + on_sprite_update(); set_pos(get_pos() - (m_col.m_bbox.get_size().as_vector() - old_size) / 2.0f); } @@ -196,18 +201,35 @@ void MovingSprite::set_action(const std::string& action, int loops, AnchorPoint anchorPoint) { Rectf old_bbox = m_col.m_bbox; - m_sprite->set_action(action, loops); - update_hitbox(); + if (!m_sprite->set_action(action, loops)) + return; + + on_sprite_update(); set_pos(get_anchor_pos(old_bbox, m_sprite->get_current_hitbox_width(), m_sprite->get_current_hitbox_height(), anchorPoint)); } +void +MovingSprite::on_sprite_update() +{ + // Update hitbox + update_hitbox(); + + // Update light sprite + m_light_sprite = m_sprite->create_linked_light_sprite(); + + // Update other linked sprites + auto linked_sprites = get_linked_sprites(); + for (const auto& [key, sprite] : linked_sprites) + sprite = m_sprite->create_linked_sprite(key); +} + bool MovingSprite::change_sprite(const std::string& new_sprite_name) { m_sprite = SpriteManager::current()->create(new_sprite_name); m_sprite_name = new_sprite_name; - update_hitbox(); + on_sprite_update(); return m_sprite->load_successful(); } @@ -236,8 +258,7 @@ MovingSprite::after_editor_set() change_sprite(get_default_sprite_name()); } m_sprite->set_action(current_action); - - update_hitbox(); + on_sprite_update(); } void diff --git a/src/object/moving_sprite.hpp b/src/object/moving_sprite.hpp index 87050496008..e95c7a896c1 100644 --- a/src/object/moving_sprite.hpp +++ b/src/object/moving_sprite.hpp @@ -17,10 +17,13 @@ #ifndef HEADER_SUPERTUX_OBJECT_MOVING_SPRITE_HPP #define HEADER_SUPERTUX_OBJECT_MOVING_SPRITE_HPP +#include "supertux/moving_object.hpp" + +#include + #include "math/anchor_point.hpp" #include "sprite/sprite.hpp" #include "sprite/sprite_ptr.hpp" -#include "supertux/moving_object.hpp" #include "video/drawing_context.hpp" #include "video/flip.hpp" @@ -142,7 +145,16 @@ class MovingSprite : public MovingObject resizing the bounding box. */ void set_action(const std::string& action, int loops, AnchorPoint anchorPoint); +public: + typedef std::unordered_map LinkedSprites; + protected: + /** Provides all linked sprites of the object, so they can be updated on main sprite change. */ + virtual LinkedSprites get_linked_sprites() { return {}; } + + /** Update the object after a sprite or sprite action change. */ + virtual void on_sprite_update(); + /** Update hitbox, based on sprite. */ virtual void update_hitbox(); @@ -154,6 +166,7 @@ class MovingSprite : public MovingObject so support for sprite switching for object types is retained. */ std::string m_default_sprite_name; SpritePtr m_sprite; + SpritePtr m_light_sprite; int m_layer; /**< Sprite's z-position. Refer to video/drawing_context.hpp for sensible values. */ Flip m_flip; diff --git a/src/object/player.cpp b/src/object/player.cpp index 132f359050d..06b566a418c 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -800,7 +800,7 @@ Player::update(float dt_sec) Vector pspeed = Vector(0, 0); Vector paccel = Vector(0, 0); Sector::get().add( - "images/particles/sparkle.sprite", + m_sprite->create_linked_sprite("sparkle-invincible"), // draw bright sparkle when there is lots of time left, // dark sparkle when invincibility is about to end (m_invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING) ? @@ -3134,7 +3134,7 @@ Player::stop_rolling(bool violent) Vector pspeed = Vector(graphicsRandom.randf(-100.f, 100.f)*(static_cast(i)-2), graphicsRandom.randf(-200.f, -150.f)); Vector paccel = Vector(0, 1000.f + graphicsRandom.randf(-100.f, 100.f)); Sector::get().add( - "images/particles/rock.sprite", "rock-"+std::to_string(i), + m_sprite->create_linked_sprite("rock-particle"), "rock-"+std::to_string(i), get_bbox().get_middle(), ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS + 6, true); } diff --git a/src/object/powerup.cpp b/src/object/powerup.cpp index 9eea696961d..e4b3b7428ad 100644 --- a/src/object/powerup.cpp +++ b/src/object/powerup.cpp @@ -21,7 +21,6 @@ #include "object/player.hpp" #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/flip_level_transformer.hpp" #include "supertux/game_session.hpp" #include "supertux/sector.hpp" @@ -31,8 +30,7 @@ PowerUp::PowerUp(const ReaderMapping& mapping) : MovingSprite(mapping, "images/powerups/egg/egg.sprite", LAYER_OBJECTS, COLGROUP_MOVING), physic(), script(), - no_physics(), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + no_physics() { parse_type(mapping); mapping.get("script", script, ""); @@ -44,8 +42,7 @@ PowerUp::PowerUp(const Vector& pos, int type) : MovingSprite(pos, "images/powerups/egg/egg.sprite", LAYER_OBJECTS, COLGROUP_MOVING), physic(), script(), - no_physics(false), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + no_physics(false) { m_type = type; on_type_change(TypeChange::INITIAL); @@ -96,7 +93,7 @@ PowerUp::get_default_sprite_name() const case COFFEE: return "images/powerups/retro/coffee.png"; case HERRING: - return "images/powerups/retro/golden_herring.png"; + return "images/powerups/retro/golden_herring.sprite"; default: return m_default_sprite_name; } @@ -130,47 +127,6 @@ PowerUp::initialize() else if (matches_sprite("images/powerups/potions/red-potion.sprite")) m_type = FLIP; } - - setup_lightsprite(); -} - -void -PowerUp::setup_lightsprite() -{ - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.0f, 0.0f, 0.0f)); - // Set default light for glow effect for default sprites. - if (matches_sprite(get_default_sprite_name())) - { - switch (m_type) - { - case EGG: - lightsprite->set_color(Color(0.2f, 0.2f, 0.0f)); - break; - case FIRE: - lightsprite->set_color(Color(0.3f, 0.0f, 0.0f)); - break; - case ICE: - lightsprite->set_color(Color(0.0f, 0.1f, 0.2f)); - break; - case AIR: - lightsprite->set_color(Color(0.15f, 0.0f, 0.15f)); - break; - case EARTH: - lightsprite->set_color(Color(0.0f, 0.3f, 0.0f)); - break; - case STAR: - lightsprite->set_color(Color(0.4f, 0.4f, 0.4f)); - break; - } - } -} - -void -PowerUp::after_editor_set() -{ - MovingSprite::after_editor_set(); - setup_lightsprite(); } void @@ -294,7 +250,7 @@ PowerUp::update(float dt_sec) Vector pspeed = Vector(0, 0); Vector paccel = Vector(0, 0); Sector::get().add( - "images/particles/sparkle.sprite", + m_sprite->create_linked_sprite("sparkle"), // draw bright sparkles when very close to Tux, dark sparkles when slightly further (disp_x*disp_x + disp_y*disp_y <= 128*128) ? // make every other a longer sparkle to make trail a bit fuzzy @@ -315,7 +271,8 @@ PowerUp::draw(DrawingContext& context) if (m_type == STAR || m_type == HERRING) m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); + if (m_light_sprite) + m_light_sprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); } ObjectSettings diff --git a/src/object/powerup.hpp b/src/object/powerup.hpp index e236d85586b..6665df5bbcc 100644 --- a/src/object/powerup.hpp +++ b/src/object/powerup.hpp @@ -60,18 +60,15 @@ class PowerUp : public MovingSprite std::vector get_patches() const override; virtual ObjectSettings get_settings() override; - virtual void after_editor_set() override; protected: /** Initialize power up sprites and other defaults */ void initialize(); - void setup_lightsprite(); protected: Physic physic; std::string script; bool no_physics; - SpritePtr lightsprite; private: PowerUp(const PowerUp&) = delete; diff --git a/src/object/rublight.cpp b/src/object/rublight.cpp index afe021e8326..32ef79c2f88 100644 --- a/src/object/rublight.cpp +++ b/src/object/rublight.cpp @@ -19,20 +19,16 @@ #include "badguy/walking_badguy.hpp" #include "object/player.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/constants.hpp" #include "supertux/flip_level_transformer.hpp" #include "video/color.hpp" #include "util/reader_mapping.hpp" - RubLight::RubLight(const ReaderMapping& mapping) : MovingSprite(mapping, "images/objects/rublight/rublight.sprite", LAYER_TILES, COLGROUP_STATIC), state(STATE_DARK), stored_energy(0), - light(SpriteManager::current()->create( - "images/objects/lightmap_light/lightmap_light.sprite")), color(1.f, 1.f, 1.f), fading_speed(5.0f), strength_multiplier(1.0f) @@ -135,12 +131,15 @@ RubLight::get_brightness() const void RubLight::draw(DrawingContext& context) { - if (state == STATE_FADING) { + if (state == STATE_FADING) + { float brightness = get_brightness(); Color col = color.multiply_linearly(brightness); - light->set_color(col); - light->set_blend(Blend::ADD); - light->draw(context.light(), get_pos(), m_layer); + if (m_light_sprite) + { + m_light_sprite->set_color(col); + m_light_sprite->draw(context.light(), get_pos(), m_layer); + } } m_sprite->draw(context.color(), get_pos(), m_layer, m_flip); diff --git a/src/object/rublight.hpp b/src/object/rublight.hpp index 9772dd2eda2..ec8a3a008e1 100644 --- a/src/object/rublight.hpp +++ b/src/object/rublight.hpp @@ -17,7 +17,6 @@ #define HEADER_SUPERTUX_OBJECT_RUBLIGHT_HPP #include "object/moving_sprite.hpp" -#include "sprite/sprite_ptr.hpp" #include "video/color.hpp" /** A triboluminescent (or something similar) block */ @@ -29,6 +28,7 @@ class RubLight final : public MovingSprite virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override; virtual void update(float dt_sec) override; virtual void draw(DrawingContext& context) override; + static std::string class_name() { return "rublight"; } virtual std::string get_class_name() const override { return class_name(); } static std::string display_name() { return _("Rublight"); } @@ -56,6 +56,7 @@ class RubLight final : public MovingSprite void rub(float strength); float get_brightness() const; +private: RubLight(const RubLight&) = delete; RubLight& operator=(const RubLight&) = delete; }; diff --git a/src/object/sprite_particle.cpp b/src/object/sprite_particle.cpp index ae7387a511c..ba41ca066da 100644 --- a/src/object/sprite_particle.cpp +++ b/src/object/sprite_particle.cpp @@ -31,21 +31,15 @@ SpriteParticle::SpriteParticle(const std::string& sprite_name, const std::string position_, anchor, velocity_, acceleration_, drawing_layer_, notimeout, color_) { - if (sprite_name == "images/particles/sparkle.sprite") - { - glow = true; - lightsprite->set_blend(Blend::ADD); - if (action=="dark") { - lightsprite->set_color(Color(0.1f, 0.1f, 0.1f)); - } - else - { - lightsprite->set_color(color_); - } +} - } - no_time_out = notimeout; - sprite->set_color(color_); +SpriteParticle::SpriteParticle(const SpriteData::LinkedSprite& linked_sprite, + const Vector& position_, AnchorPoint anchor, const Vector& velocity_, const Vector& acceleration_, + int drawing_layer_, bool notimeout, Color color_) : + SpriteParticle(SpriteManager::current()->create(linked_sprite.file), linked_sprite.action.empty() ? "default" : linked_sprite.action, + position_, anchor, velocity_, acceleration_, + drawing_layer_, notimeout, color_) +{ } SpriteParticle::SpriteParticle(SpritePtr sprite_, const std::string& action, @@ -56,8 +50,7 @@ SpriteParticle::SpriteParticle(SpritePtr sprite_, const std::string& action, velocity(velocity_), acceleration(acceleration_), drawing_layer(drawing_layer_), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-tiny.sprite")), - glow(false), + lightsprite(), no_time_out(false), color(Color::WHITE) { @@ -67,8 +60,17 @@ SpriteParticle::SpriteParticle(SpritePtr sprite_, const std::string& action, position -= get_anchor_pos(sprite->get_current_hitbox(), anchor); no_time_out = notimeout; + + lightsprite = sprite->create_linked_light_sprite(); + if (lightsprite) + { + if (!sprite->get_linked_light_sprite()->color) + lightsprite->set_color(color_); + } } + + SpriteParticle::~SpriteParticle() { remove_me(); @@ -102,13 +104,11 @@ SpriteParticle::draw(DrawingContext& context) Vector draw_pos = position + velocity * context.get_time_offset(); sprite->draw(context.color(), draw_pos, drawing_layer); - //Sparkles glow in the dark - if (glow) + if (lightsprite) { sprite->draw(context.light(), draw_pos, drawing_layer); lightsprite->draw(context.light(), draw_pos + Vector(12, 12), 0); } - } /* EOF */ diff --git a/src/object/sprite_particle.hpp b/src/object/sprite_particle.hpp index ae5dad30dfc..0c9b099192b 100644 --- a/src/object/sprite_particle.hpp +++ b/src/object/sprite_particle.hpp @@ -19,6 +19,7 @@ #define HEADER_SUPERTUX_OBJECT_SPRITE_PARTICLE_HPP #include "math/anchor_point.hpp" +#include "sprite/sprite_data.hpp" #include "sprite/sprite_ptr.hpp" #include "supertux/game_object.hpp" #include "video/color.hpp" @@ -33,6 +34,10 @@ class SpriteParticle final : public GameObject const Vector& position, AnchorPoint anchor, const Vector& velocity, const Vector& acceleration, int drawing_layer = LAYER_OBJECTS-1, bool notimeout = false, Color color = Color::WHITE); + SpriteParticle(const SpriteData::LinkedSprite& linked_sprite, + const Vector& position, AnchorPoint anchor, + const Vector& velocity, const Vector& acceleration, + int drawing_layer = LAYER_OBJECTS-1, bool notimeout = false, Color color = Color::WHITE); SpriteParticle(const std::string& sprite_name, const std::string& action, const Vector& position, AnchorPoint anchor, const Vector& velocity, const Vector& acceleration, @@ -54,7 +59,6 @@ class SpriteParticle final : public GameObject Vector acceleration; int drawing_layer; SpritePtr lightsprite; - bool glow; bool no_time_out; Color color; diff --git a/src/object/star.cpp b/src/object/star.cpp index ca5be430bae..99e130d1a1b 100644 --- a/src/object/star.cpp +++ b/src/object/star.cpp @@ -20,7 +20,6 @@ #include "object/player.hpp" #include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/sector.hpp" static const float INITIALJUMP = -400; @@ -29,13 +28,9 @@ static const float JUMPSTAR_SPEED = -300; Star::Star(const Vector& pos, Direction direction, const std::string& custom_sprite) : MovingSprite(pos, custom_sprite.empty() ? "images/powerups/star/star.sprite" : custom_sprite, LAYER_OBJECTS, COLGROUP_MOVING), - physic(), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + physic() { physic.set_velocity((direction == Direction::LEFT) ? -STAR_SPEED : STAR_SPEED, INITIALJUMP); - //set light for glow effect - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.4f, 0.4f, 0.4f)); } void @@ -56,7 +51,7 @@ Star::update(float dt_sec) Vector pspeed = Vector(0, 0); Vector paccel = Vector(0, 0); Sector::get().add( - "images/particles/sparkle.sprite", + m_sprite->create_linked_sprite("sparkle"), // draw bright sparkles when very close to Tux, dark sparkles when slightly further (disp_x*disp_x + disp_y*disp_y <= 128*128) ? // make every other a longer sparkle to make trail a bit fuzzy @@ -67,13 +62,6 @@ Star::update(float dt_sec) } } -void -Star::draw(DrawingContext& context) -{ - MovingSprite::draw(context); - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); -} - void Star::collision_solid(const CollisionHit& hit) { diff --git a/src/object/star.hpp b/src/object/star.hpp index f019757707b..795c8efe041 100644 --- a/src/object/star.hpp +++ b/src/object/star.hpp @@ -29,7 +29,6 @@ class Star final : public MovingSprite virtual GameObjectClasses get_class_types() const override { return MovingSprite::get_class_types().add(typeid(Star)); } virtual void update(float dt_sec) override; - virtual void draw(DrawingContext& context) override; virtual void collision_solid(const CollisionHit& hit) override; virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override; @@ -38,7 +37,6 @@ class Star final : public MovingSprite private: Physic physic; - SpritePtr lightsprite; private: Star(const Star&) = delete; diff --git a/src/object/torch.cpp b/src/object/torch.cpp index 0bf8a7a56cd..638b7c49e53 100644 --- a/src/object/torch.cpp +++ b/src/object/torch.cpp @@ -22,16 +22,14 @@ #include "object/player.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "supertux/flip_level_transformer.hpp" #include "util/reader_mapping.hpp" Torch::Torch(const ReaderMapping& reader) : MovingSprite(reader, "images/objects/torch/torch1.sprite", LAYER_TILES), m_light_color(1.f, 1.f, 1.f), - m_flame(SpriteManager::current()->create("images/objects/torch/flame.sprite")), - m_flame_glow(SpriteManager::current()->create("images/objects/torch/flame_glow.sprite")), - m_flame_light(SpriteManager::current()->create("images/objects/torch/flame_light.sprite")), + m_flame(m_sprite->create_linked_sprite("flame")), + m_flame_glow(m_sprite->create_linked_sprite("glow")), m_burning(true) { reader.get("burning", m_burning, true); @@ -41,17 +39,31 @@ Torch::Torch(const ReaderMapping& reader) : if (!reader.get("color", vColor)) vColor = { 1.f, 1.f, 1.f }; m_flame_glow->set_blend(Blend::ADD); - m_flame_light->set_blend(Blend::ADD); if (vColor.size() >= 3) { m_light_color = Color(vColor); m_flame->set_color(m_light_color); m_flame_glow->set_color(m_light_color); - m_flame_light->set_color(m_light_color); + if (m_light_sprite) + m_light_sprite->set_color(m_light_color); } + + m_flame->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + m_light_sprite->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + m_flame_glow->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + set_group(COLGROUP_TOUCHABLE); } +MovingSprite::LinkedSprites +Torch::get_linked_sprites() +{ + return { + { "flame", m_flame }, + { "glow", m_flame_glow } + }; +} + void Torch::draw(DrawingContext& context) { @@ -60,13 +72,13 @@ Torch::draw(DrawingContext& context) Vector pos = get_pos(); if (m_flip != NO_FLIP) pos.y -= 24.0f; m_flame->draw(context.color(), pos, m_layer - 1, m_flip); - m_flame->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); - m_flame_light->draw(context.light(), pos, m_layer); - m_flame_light->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + if (m_light_sprite) + { + m_light_sprite->draw(context.light(), pos, m_layer); + } m_flame_glow->draw(context.color(), pos, m_layer - 1, m_flip); - m_flame_glow->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); } m_sprite->draw(context.color(), get_pos(), m_layer - 1, m_flip); @@ -108,7 +120,12 @@ Torch::after_editor_set() m_flame->set_color(m_light_color); m_flame_glow->set_color(m_light_color); - m_flame_light->set_color(m_light_color); + if (m_light_sprite) + m_light_sprite->set_color(m_light_color); + + m_flame->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + m_light_sprite->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); + m_flame_glow->set_action(m_light_color.greyscale() >= 1.f ? "default" : "greyscale"); } bool diff --git a/src/object/torch.hpp b/src/object/torch.hpp index e8be5b8b74e..bf248105249 100644 --- a/src/object/torch.hpp +++ b/src/object/torch.hpp @@ -49,6 +49,7 @@ class Torch final : public MovingSprite virtual GameObjectClasses get_class_types() const override { return MovingSprite::get_class_types().add(typeid(Torch)); } virtual ObjectSettings get_settings() override; + virtual LinkedSprites get_linked_sprites() override; virtual void after_editor_set() override; virtual void on_flip(float height) override; diff --git a/src/object/weak_block.cpp b/src/object/weak_block.cpp index 00132f612e2..7791cf16c90 100644 --- a/src/object/weak_block.cpp +++ b/src/object/weak_block.cpp @@ -27,7 +27,6 @@ #include "supertux/globals.hpp" #include "supertux/sector.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" #include "util/log.hpp" #include "util/reader_mapping.hpp" #include "util/writer.hpp" @@ -35,7 +34,7 @@ WeakBlock::WeakBlock(const ReaderMapping& mapping) : MovingSprite(mapping, "images/objects/weak_block/meltbox.sprite", LAYER_OBJECTS + 10, COLGROUP_STATIC), state(STATE_NORMAL), - lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite")) + m_burn_sprite() { // Older levels utilize hardcoded behaviour from the "linked" property. if (get_version() == 1) @@ -55,17 +54,33 @@ WeakBlock::WeakBlock(const ReaderMapping& mapping) : parse_type(mapping); } - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.3f, 0.2f, 0.1f)); - if (m_type == HAY) + { + m_burn_sprite = m_sprite->create_linked_sprite("burn-light"); + m_burn_sprite->set_blend(Blend::ADD); + m_burn_sprite->set_color(Color(0.3f, 0.2f, 0.1f)); SoundManager::current()->preload("sounds/fire.ogg"); // TODO: Use own sound? + } else + { SoundManager::current()->preload("sounds/sizzle.ogg"); + } set_action("normal"); } +MovingSprite::LinkedSprites +WeakBlock::get_linked_sprites() +{ + if (m_type == HAY) + { + return { + { "burn-light", m_burn_sprite } + }; + } + return {}; +} + void WeakBlock::update_version() { @@ -182,11 +197,11 @@ WeakBlock::update(float ) // cause burn light to flicker randomly if (m_type == HAY) { if (graphicsRandom.rand(10) >= 7) { - lightsprite->set_color(Color(0.2f + graphicsRandom.randf(20.0f) / 100.0f, - 0.1f + graphicsRandom.randf(20.0f)/100.0f, - 0.1f)); + m_burn_sprite->set_color(Color(0.2f + graphicsRandom.randf(20.0f) / 100.0f, + 0.1f + graphicsRandom.randf(20.0f)/100.0f, + 0.1f)); } else - lightsprite->set_color(Color(0.3f, 0.2f, 0.1f)); + m_burn_sprite->set_color(Color(0.3f, 0.2f, 0.1f)); } if (m_sprite->animation_done()) { @@ -194,9 +209,6 @@ WeakBlock::update(float ) set_action("disintegrating", 1); spreadHit(); set_group(COLGROUP_DISABLED); - lightsprite = SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-tiny.sprite"); - lightsprite->set_blend(Blend::ADD); - lightsprite->set_color(Color(0.3f, 0.2f, 0.1f)); } break; @@ -214,10 +226,9 @@ void WeakBlock::draw(DrawingContext& context) { MovingSprite::draw(context); - if (m_type == HAY && (state != STATE_NORMAL)) - { - lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); - } + + if (m_burn_sprite && state != STATE_NORMAL) + m_burn_sprite->draw(context.light(), m_col.m_bbox.get_middle(), 0); } void diff --git a/src/object/weak_block.hpp b/src/object/weak_block.hpp index 8c9f5724f54..885f5d1b57f 100644 --- a/src/object/weak_block.hpp +++ b/src/object/weak_block.hpp @@ -48,6 +48,9 @@ class WeakBlock final : public MovingSprite void startBurning(); +protected: + LinkedSprites get_linked_sprites() override; + private: virtual HitResponse collision_bullet(Bullet& bullet, const CollisionHit& hit); @@ -71,7 +74,7 @@ class WeakBlock final : public MovingSprite private: State state; - SpritePtr lightsprite; + SpritePtr m_burn_sprite; private: WeakBlock(const WeakBlock&) = delete; diff --git a/src/sprite/sprite.cpp b/src/sprite/sprite.cpp index b3dc6bf58bd..06876da976a 100644 --- a/src/sprite/sprite.cpp +++ b/src/sprite/sprite.cpp @@ -18,6 +18,7 @@ #include +#include "sprite/sprite_manager.hpp" #include "supertux/direction.hpp" #include "supertux/globals.hpp" #include "util/log.hpp" @@ -66,42 +67,42 @@ Sprite::clone() const return SpritePtr(new Sprite(*this)); } -void +bool Sprite::set_action(const std::string& name, const Direction& dir, int loops) { if (dir == Direction::NONE) - set_action(name, loops); + return set_action(name, loops); else - set_action(name + "-" + dir_to_string(dir), loops); + return set_action(name + "-" + dir_to_string(dir), loops); } -void +bool Sprite::set_action(const Direction& dir, const std::string& name, int loops) { if (dir == Direction::NONE) - set_action(name, loops); + return set_action(name, loops); else - set_action(dir_to_string(dir) + "-" + name, loops); + return set_action(dir_to_string(dir) + "-" + name, loops); } -void +bool Sprite::set_action(const Direction& dir, int loops) { - set_action(dir_to_string(dir), loops); + return set_action(dir_to_string(dir), loops); } -void +bool Sprite::set_action(const std::string& name, int loops) { if (m_action && m_action->name == name) - return; + return false; const SpriteData::Action* newaction = m_data.get_action(name); if (!newaction) { // HACK: Lots of things trigger this message therefore turning it into a warning // would make it quite annoying - log_debug << "Action '" << name << "' not found." << std::endl; - return; + log_debug << m_data.m_filename << ": Action '" << name << "' not found." << std::endl; + return false; } // Automatically resume if a new action is set @@ -112,7 +113,7 @@ Sprite::set_action(const std::string& name, int loops) { m_action = newaction; update(); - return; + return true; } // If the new action has a loops property, @@ -126,6 +127,7 @@ Sprite::set_action(const std::string& name, int loops) } m_action = newaction; + return true; } bool @@ -140,7 +142,8 @@ Sprite::update() float frame_inc = m_action->fps * (g_game_time - m_last_ticks); m_last_ticks = g_game_time; - if (m_is_paused) return; + if (m_is_paused) + return; m_frame += frame_inc; @@ -177,11 +180,12 @@ Sprite::draw(Canvas& canvas, const Vector& pos, int layer, context.set_alpha(context.get_alpha() * m_alpha); canvas.draw_surface(m_action->surfaces[m_frameidx], - pos - Vector(m_action->x_offset, flip == NO_FLIP ? m_action->y_offset : (static_cast(m_action->surfaces[m_frameidx]->get_height()) - m_action->y_offset - m_action->hitbox_h)), - m_angle, - m_color, - m_blend, - layer); + pos - Vector(m_action->x_offset, flip == NO_FLIP ? m_action->y_offset : + (static_cast(m_action->surfaces[m_frameidx]->get_height()) - m_action->y_offset - m_action->hitbox_h + m_action->flip_offset)), + m_angle, + m_color, + m_blend, + layer); context.pop_transform(); } @@ -209,6 +213,69 @@ Sprite::draw_scaled(Canvas& canvas, const Rectf& dest_rect, int layer, context.pop_transform(); } +const std::optional& +Sprite::get_linked_light_sprite() const +{ + return m_action->linked_light_sprite ? m_action->linked_light_sprite : m_data.linked_light_sprite; +} + +SpritePtr +Sprite::create_linked_light_sprite() const +{ + const auto& sprite_data = get_linked_light_sprite(); + + SpritePtr sprite; + if (sprite_data) + { + sprite = SpriteManager::current()->create(sprite_data->file); + if (!sprite_data->action.empty()) + sprite->set_action(sprite_data->action); + if (sprite_data->color) + sprite->set_color(*sprite_data->color); + sprite->set_blend(Blend::ADD); + } + return sprite; +} + +bool +Sprite::has_linked_sprite(const std::string& key) const +{ + return m_action->linked_sprites.find(key) != m_action->linked_sprites.end() || + m_data.linked_sprites.find(key) != m_data.linked_sprites.end(); +} + +const SpriteData::LinkedSprite& +Sprite::get_linked_sprite(const std::string& key) const +{ + auto it = m_action->linked_sprites.find(key); + if (it != m_action->linked_sprites.end()) + return it->second; + + it = m_data.linked_sprites.find(key); + if (it == m_data.linked_sprites.end()) // No linked sprite with such key + { + log_warning << m_data.m_filename << ": No linked sprite with key '" << key << "'." << std::endl; + + static SpriteData::LinkedSprite dummy_sprite_data; + return dummy_sprite_data; // Empty linked sprite with an empty filename leads to a dummy sprite + } + + return it->second; +} + +SpritePtr +Sprite::create_linked_sprite(const std::string& key) const +{ + const auto& sprite_data = get_linked_sprite(key); + + SpritePtr sprite = SpriteManager::current()->create(sprite_data.file); + if (sprite_data.action.empty()) + sprite->set_animation_loops(sprite_data.loops); + else + sprite->set_action(sprite_data.action, sprite_data.loops); + return sprite; +} + int Sprite::get_width() const { diff --git a/src/sprite/sprite.hpp b/src/sprite/sprite.hpp index 76c85c326a9..8885089d01c 100644 --- a/src/sprite/sprite.hpp +++ b/src/sprite/sprite.hpp @@ -43,22 +43,22 @@ class Sprite final Flip flip = NO_FLIP); /** Set action (or state) */ - void set_action(const std::string& name, int loops = -1); + bool set_action(const std::string& name, int loops = -1); /** Composes action (or state) string from an action name and a particular direction * in the form of "name-direction", eg. "walk-left" */ - void set_action(const std::string& name, const Direction& dir, int loops = -1); + bool set_action(const std::string& name, const Direction& dir, int loops = -1); /** Composes action (or state) string from an action name and a particular direction * in the form of "direction-name", eg. "left-up" */ - void set_action(const Direction& dir, const std::string& name, int loops = -1); + bool set_action(const Direction& dir, const std::string& name, int loops = -1); /** Composes action (or state) string from a particular direction * in the form of "direction", e.g. "left" */ - void set_action(const Direction& dir, int loops = -1); + bool set_action(const Direction& dir, int loops = -1); /** Set number of animation cycles until animation stops */ void set_animation_loops(int loops = -1) { m_animation_loops = loops; } @@ -88,6 +88,15 @@ class Sprite final /** Get current action name */ const std::string& get_action() const { return m_action->name; } + /** Get linked light sprite */ + const std::optional& get_linked_light_sprite() const; + SpritePtr create_linked_light_sprite() const; + + /** Get linked sprite by key */ + bool has_linked_sprite(const std::string& key) const; + const SpriteData::LinkedSprite& get_linked_sprite(const std::string& key) const; + SpritePtr create_linked_sprite(const std::string& key) const; + int get_width() const; int get_height() const; @@ -114,6 +123,7 @@ class Sprite final void set_color(const Color& color); Color get_color() const; + inline Color& get_color() { return m_color; } void set_alpha(float alpha); float get_alpha() const; diff --git a/src/sprite/sprite_data.cpp b/src/sprite/sprite_data.cpp index 3a70d16130d..60851d6b80b 100644 --- a/src/sprite/sprite_data.cpp +++ b/src/sprite/sprite_data.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -34,10 +35,64 @@ #include "video/surface.hpp" #include "video/texture_manager.hpp" +LinkedSpritesContainer::LinkedSpritesContainer() : + linked_light_sprite(), + linked_sprites() +{ +} + +void +LinkedSpritesContainer::parse_linked_sprites(const ReaderMapping& mapping) +{ + auto iter_sprites = mapping.get_iter(); + while (iter_sprites.next()) + { + const auto& sx = iter_sprites.as_mapping().get_sexp(); + const auto& arr = sx.as_array(); + + std::string filepath = FileSystem::join(mapping.get_doc().get_directory(), arr[1].as_string()); + if (!PHYSFS_exists(filepath.c_str())) // If file path is not relative to current directory, make it relative to root + filepath = arr[1].as_string(); + + const std::string key = arr[0].as_string(); + if (key == "light") // The key "light" is reserved for light sprites + { + linked_light_sprite = LinkedLightSprite(filepath); + + if (arr.size() >= 3) // Default action has been specified + { + linked_light_sprite->action = arr[2].as_string(); + + if (arr.size() >= 6) // Color has been specified + { + linked_light_sprite->color = Color(arr[3].as_float(), arr[4].as_float(), + arr[5].as_float()); + } + } + } + else + { + LinkedSprite linked_sprite = LinkedSprite(filepath); + + if (arr.size() >= 3) // Default action has been specified + { + linked_sprite.action = arr[2].as_string(); + + if (arr.size() >= 4) // Default action loops have been specified + linked_sprite.loops = arr[3].as_int(); + } + + linked_sprites[key] = std::move(linked_sprite); + } + } +} + + SpriteData::Action::Action() : name(), x_offset(0), y_offset(0), + flip_offset(0), hitbox_w(0), hitbox_h(0), hitbox_unisolid(false), @@ -128,8 +183,7 @@ SpriteData::load() { // Load single image auto surface = Surface::from_file(m_filename); - if (!TextureManager::current()->last_load_successful()) - throw std::runtime_error("Cannot load image."); + m_load_successful = TextureManager::current()->last_load_successful(); // Create action, if it doesn't exist { @@ -142,6 +196,7 @@ SpriteData::load() } } actions["default"]->reset(surface); + return; } m_load_successful = true; @@ -154,9 +209,17 @@ SpriteData::parse(const ReaderMapping& mapping) while (iter.next()) { if (iter.get_key() == "action") + { parse_action(iter.as_mapping()); + } + else if (iter.get_key() == "linked-sprites") + { + parse_linked_sprites(iter.as_mapping()); + } else + { log_warning << "Unknown sprite field: " << iter.get_key() << std::endl; + } } if (actions.empty()) @@ -204,6 +267,7 @@ SpriteData::parse_action(const ReaderMapping& mapping) throw std::runtime_error("Hitbox should specify 2/4 coordinates!"); } } + mapping.get("flip-offset", action->flip_offset); mapping.get("unisolid", action->hitbox_unisolid); mapping.get("fps", action->fps); if (mapping.get("loops", action->loops)) @@ -224,6 +288,12 @@ SpriteData::parse_action(const ReaderMapping& mapping) action->family_name = "::" + action->name; } + std::optional linked_sprites_mapping; + if (mapping.get("linked-sprites", linked_sprites_mapping)) + { + action->parse_linked_sprites(*linked_sprites_mapping); + } + std::string mirror_action; std::string flip_action; std::string clone_action; diff --git a/src/sprite/sprite_data.hpp b/src/sprite/sprite_data.hpp index 5137f5b50f8..13fcdadbbc1 100644 --- a/src/sprite/sprite_data.hpp +++ b/src/sprite/sprite_data.hpp @@ -21,12 +21,53 @@ #include #include #include +#include +#include +#include "video/color.hpp" #include "video/surface_ptr.hpp" class ReaderMapping; -class SpriteData final +class LinkedSpritesContainer +{ + friend class Sprite; + +protected: + LinkedSpritesContainer(); + +public: + void parse_linked_sprites(const ReaderMapping& mapping); + +public: + struct LinkedSprite final + { + LinkedSprite(const std::string& file_ = {}) : + file(file_), action(), loops(-1) + {} + + std::string file; + std::string action; + int loops; + }; + struct LinkedLightSprite final + { + LinkedLightSprite(const std::string& file_ = {}) : + file(file_), action(), color() + {} + + std::string file; + std::string action; + std::optional color; + }; + typedef std::unordered_map LinkedSprites; + +protected: + std::optional linked_light_sprite; + LinkedSprites linked_sprites; +}; + +class SpriteData final : public LinkedSpritesContainer { friend class Sprite; @@ -36,7 +77,7 @@ class SpriteData final void load(); private: - struct Action final + struct Action final : public LinkedSpritesContainer { Action(); @@ -47,6 +88,7 @@ class SpriteData final /** Position correction */ float x_offset; float y_offset; + float flip_offset; /** Hitbox width */ float hitbox_w; diff --git a/src/trigger/door.cpp b/src/trigger/door.cpp index c35136be8f6..d96970c09cc 100644 --- a/src/trigger/door.cpp +++ b/src/trigger/door.cpp @@ -19,9 +19,8 @@ #include "audio/sound_manager.hpp" #include "math/random.hpp" #include "object/player.hpp" -#include "object/sprite_particle.hpp" #include "sprite/sprite.hpp" -#include "sprite/sprite_manager.hpp" +#include "object/sprite_particle.hpp" #include "supertux/fadetoblack.hpp" #include "supertux/game_session.hpp" #include "supertux/screen_manager.hpp" @@ -40,7 +39,7 @@ Door::Door(const ReaderMapping& mapping) : m_target_sector(), m_target_spawnpoint(), m_script(), - m_lock_sprite(SpriteManager::current()->create("images/objects/door/door_lock.sprite")), + m_lock_sprite(m_sprite->create_linked_sprite("lock")), m_stay_open_timer(), m_unlocking_timer(), m_lock_warn_timer(), @@ -71,6 +70,14 @@ Door::Door(const ReaderMapping& mapping) : SoundManager::current()->preload("sounds/turnkey.ogg"); } +MovingSprite::LinkedSprites +Door::get_linked_sprites() +{ + return { + { "lock", m_lock_sprite } + }; +} + ObjectSettings Door::get_settings() { @@ -92,6 +99,7 @@ Door::after_editor_set() { SpritedTrigger::after_editor_set(); + m_state = m_locked ? DoorState::LOCKED : DoorState::CLOSED; m_lock_sprite->set_color(m_lock_color); } @@ -133,8 +141,8 @@ Door::update(float ) case UNLOCKING: if (m_unlocking_timer.check()) { - Sector::get().add("images/objects/door/door_lock.sprite", - "default", get_bbox().get_middle(), ANCHOR_MIDDLE, Vector(0.f, -300.f), Vector(0.f, 1000.f), LAYER_OBJECTS - 2, true, m_lock_color); + Sector::get().add(m_sprite->get_linked_sprite("lock"), + get_bbox().get_middle(), ANCHOR_MIDDLE, Vector(0.f, -300.f), Vector(0.f, 1000.f), LAYER_OBJECTS - 2, true, m_lock_color); m_unlocking_timer.stop(); m_state = DoorState::CLOSED; } diff --git a/src/trigger/door.hpp b/src/trigger/door.hpp index 7b095c33157..f83242a7322 100644 --- a/src/trigger/door.hpp +++ b/src/trigger/door.hpp @@ -48,6 +48,9 @@ class Door final : public SpritedTrigger Color get_lock_color() const { return m_lock_color; } +protected: + LinkedSprites get_linked_sprites() override; + private: enum DoorState { CLOSED,