diff --git a/assets/levels/COMMON/OBJ.TIM b/assets/levels/COMMON/OBJ.TIM
index 1933596..e0e464c 100644
Binary files a/assets/levels/COMMON/OBJ.TIM and b/assets/levels/COMMON/OBJ.TIM differ
diff --git a/assets/levels/COMMON/obj.png b/assets/levels/COMMON/obj.png
index 727e581..6e6b47f 100644
Binary files a/assets/levels/COMMON/obj.png and b/assets/levels/COMMON/obj.png differ
diff --git a/assets/levels/COMMON/obj_common_designtiles.png b/assets/levels/COMMON/obj_common_designtiles.png
index b0e90c4..378e9de 100644
Binary files a/assets/levels/COMMON/obj_common_designtiles.png and b/assets/levels/COMMON/obj_common_designtiles.png differ
diff --git a/assets/levels/COMMON/objects_common.toml b/assets/levels/COMMON/objects_common.toml
index b1e0aa8..3e22b11 100644
--- a/assets/levels/COMMON/objects_common.toml
+++ b/assets/levels/COMMON/objects_common.toml
@@ -308,6 +308,37 @@ duration = 0
frames = [[144, 72, 32, 8]]
loopback = 0
+
+# ============
+
+[explosion]
+
+[[explosion.animations]]
+name = "small"
+id = 0
+duration = 4
+frames = [
+ [48, 136, 32, 32],
+ [80, 136, 32, 32],
+ [112, 136, 32, 32],
+ [144, 136, 48, 48],
+ [192, 136, 48, 48],
+]
+loopback = -1
+
+[[explosion.animations]]
+name = "big"
+id = 0
+duration = 4
+frames = [
+ [48, 136, 32, 32],
+ [80, 168, 32, 32],
+ [112, 168, 32, 32],
+ [144, 136, 48, 48],
+ [192, 136, 48, 48],
+]
+loopback = -1
+
# ============
# Dummy objects
# ============
diff --git a/assets/levels/COMMON/objects_common.tsx b/assets/levels/COMMON/objects_common.tsx
index 4f57b71..9c8956c 100644
--- a/assets/levels/COMMON/objects_common.tsx
+++ b/assets/levels/COMMON/objects_common.tsx
@@ -49,4 +49,5 @@
+
diff --git a/assets/levels/COMMON/objs_common_texture.xcf b/assets/levels/COMMON/objs_common_texture.xcf
index 6f9e8f2..e6319a4 100644
Binary files a/assets/levels/COMMON/objs_common_texture.xcf and b/assets/levels/COMMON/objs_common_texture.xcf differ
diff --git a/include/object.h b/include/object.h
index 15c71c0..b620bab 100644
--- a/include/object.h
+++ b/include/object.h
@@ -24,6 +24,7 @@ typedef enum {
OBJ_SPRING_RED_DIAGONAL = 0x07,
OBJ_SWITCH = 0x08,
OBJ_GOAL_SIGN = 0x09,
+ OBJ_EXPLOSION = 0x0a,
} ObjectType;
#define MASK_FLIP_FLIPX 0x1 // Flip on X axis
diff --git a/src/main.c b/src/main.c
index 7761f1e..44a8542 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,7 +26,7 @@
Locations of common textures on frame buffer:
================================================
Player 1: 320x0; CLUT: 0x480
- Common objects: 576x0; CLUT: 0x481
+ Common objects: 576x0; CLUT: 0x481 (8-bit only)
Level tiles: 448x0; CLUT: 0x482 (if exists)
Level BG0: 448x256; CLUT: 0x483 (4-bit only)
Level BG1: 512x256; CLUT: 0x484 (4-bit only)
diff --git a/src/object.c b/src/object.c
index acec051..83ddf6f 100644
--- a/src/object.c
+++ b/src/object.c
@@ -60,6 +60,7 @@ load_object_table(const char *filename, ObjectTable *tbl)
// Entry ID, always sequential; discarded for now
uint8_t _id = get_byte(bytes, &b); (void)(_id);
+ /* printf("Load object 0x%04x\n", _id); */
uint8_t has_fragment = get_byte(bytes, &b);
entry->num_animations = get_short_be(bytes, &b);
diff --git a/src/object_state.c b/src/object_state.c
index b61417d..0a8b5ff 100644
--- a/src/object_state.c
+++ b/src/object_state.c
@@ -272,7 +272,7 @@ begin_render_routine:
// Sprites: 576x0
// CLUT: 0x481
- poly->tpage = getTPage(0, 0, 576, 0);
+ poly->tpage = getTPage(1, 0, 576, 0);
poly->clut = getClut(0, 481);
sort_prim(poly, state->id == OBJ_RING ? OTZ_LAYER_OBJECTS : OTZ_LAYER_PLAYER);
diff --git a/src/object_state_update.c b/src/object_state_update.c
index b6033b0..7e4a621 100644
--- a/src/object_state_update.c
+++ b/src/object_state_update.c
@@ -42,6 +42,7 @@ static void _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos,
static void _spring_diagonal_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_red);
static void _checkpoint_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos);
static void _spikes_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos);
+static void _explosion_update(ObjectState *state, ObjectTableEntry *, VECTOR *);
// Player hitbox information. Calculated once per frame.
static int32_t player_vx, player_vy; // Top left corner of player hitbox
@@ -100,6 +101,7 @@ object_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos)
case OBJ_SPRING_RED_DIAGONAL: _spring_diagonal_update(state, typedata, pos, 1); break;
case OBJ_CHECKPOINT: _checkpoint_update(state, typedata, pos); break;
case OBJ_SPIKES: _spikes_update(state, typedata, pos); break;
+ case OBJ_EXPLOSION: _explosion_update(state, typedata, pos); break;
}
}
@@ -247,6 +249,12 @@ _monitor_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
level_score_count += 10;
sound_play_vag(sfx_pop, 0);
+ // Create explosion effect
+ PoolObject *explosion = object_pool_create(OBJ_EXPLOSION);
+ explosion->freepos.vx = (pos->vx << 12);
+ explosion->freepos.vy = (pos->vy << 12);
+ explosion->state.anim_state.animation = 0; // Small explosion
+
// TODO: This should be the behaviour of our monitor particles
switch(((MonitorExtra *)state->extra)->kind) {
case MONITOR_KIND_RING:
@@ -495,3 +503,13 @@ _spikes_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
}
}
}
+
+
+static void
+_explosion_update(ObjectState *state, ObjectTableEntry *, VECTOR *)
+{
+ // Explosions are simple particles: their animation is finished?
+ // If so, destroy.
+ if(state->anim_state.animation == OBJ_ANIMATION_NO_ANIMATION)
+ state->props |= OBJ_FLAG_DESTROYED;
+}
diff --git a/src/screen_level.c b/src/screen_level.c
index 8f779a5..76b57bd 100644
--- a/src/screen_level.c
+++ b/src/screen_level.c
@@ -262,8 +262,8 @@ screen_level_draw(void *d)
/* render_model(&data->ring); */
- render_lvl(&leveldata, &map128, &map16, &obj_table_common, camera.pos.vx, camera.pos.vy);
object_pool_render(&obj_table_common, camera.pos.vx, camera.pos.vy);
+ render_lvl(&leveldata, &map128, &map16, &obj_table_common, camera.pos.vx, camera.pos.vy);
parallax_draw(&data->parallax, &camera);
// Gouraud-shaded cube
diff --git a/tools/cookobj/datatypes.py b/tools/cookobj/datatypes.py
index aff876c..1c3448d 100644
--- a/tools/cookobj/datatypes.py
+++ b/tools/cookobj/datatypes.py
@@ -26,16 +26,21 @@ class DummyObjectId(Enum):
class ObjectId(Enum):
- RING = 0
- MONITOR = 1
- SPIKES = 2
- CHECKPOINT = 3
- SPRING_YELLOW = 4
- SPRING_RED = 5
- SPRING_YELLOW_DIAGONAL = 6
- SPRING_RED_DIAGONAL = 7
- SWITCH = 8
- GOAL_SIGN = 9
+ RING = 0x00
+ MONITOR = 0x01
+ SPIKES = 0x02
+ CHECKPOINT = 0x03
+ SPRING_YELLOW = 0x04
+ SPRING_RED = 0x05
+ SPRING_YELLOW_DIAGONAL = 0x06
+ SPRING_RED_DIAGONAL = 0x07
+ SWITCH = 0x08
+ GOAL_SIGN = 0x09
+
+ # Certain objects simply cannot be placed.
+ # This happens when the object in question is a particle
+ # or effect.
+ EXPLOSION = 0x0a
@staticmethod
def get(name):
@@ -50,6 +55,7 @@ class ObjectId(Enum):
"spring_red_diagonal": ObjectId.SPRING_RED_DIAGONAL,
"goal_sign": ObjectId.GOAL_SIGN,
"switch": ObjectId.SWITCH,
+ "explosion": ObjectId.EXPLOSION,
}
result = switch.get(name.lower())
assert result is not None, f"Unknown common object {name}"
diff --git a/tools/layouts/otd.hexpat b/tools/layouts/otd.hexpat
index 69399ab..e9faf18 100644
--- a/tools/layouts/otd.hexpat
+++ b/tools/layouts/otd.hexpat
@@ -11,6 +11,7 @@ enum CommonId: s8 {
SPRING_RED_DIAGONAL = 7,
GOAL_SIGN = 8,
SWITCH = 9,
+ EXPLOSION = 10,
};
bitfield FlipMask {