// Copyright (c) 2023 Alex Diener. All rights reserved. #include "PROJECT_NAME/Atoms.h" #include "PROJECT_NAME/EntityComponent_attack.h" #include "PROJECT_NAME/EntityDestructibleTile.h" #include "PROJECT_NAME/RoomState.h" #include "PROJECT_NAME/Sprites.h" #include "PROJECT_NAME/Utilities.h" #define stemobject_implementation EntityDestructibleTile stemobject_vtable_begin(); stemobject_vtable_entry(createWithEncodedState); stemobject_vtable_entry(initWithEncodedState); stemobject_vtable_entry(copy); stemobject_vtable_entry(initCopy); stemobject_vtable_entry(dispose); stemobject_vtable_entry(getComponent); stemobject_vtable_entry(isEqual); stemobject_vtable_entry(enumerateProperties); stemobject_vtable_entry(undoActionPerformed); stemobject_vtable_end(); EntityDestructibleTile * EntityDestructibleTile_create(Vector2i position, bool destroyed, struct RoomState * roomState) { stemobject_create_implementation(init, position, destroyed, roomState) } static void destroyTile(EntityDestructibleTile * self) { self->destroyed = true; self->spriteComponent.spriteID = SPRITE_ID_WALL_DESTROYED; self->spriteComponent.drawLayer = DRAW_LAYER_FLOOR; EventDispatcher_dispatchEvent(self->roomState->eventDispatcher, ATOM_event_tile_destroyed, self); } static bool collisionCallback(struct GameEntity * collidingEntity, Vector2i fromDirection, void * context) { EntityDestructibleTile * self = context; EntityComponent_attack * attackComponent = call_virtual(getComponent, collidingEntity, COMPONENT_ATTACK); if (attackComponent != NULL && (attackComponent->type & ATTACK_DESTROY_WALL)) { destroyTile(self); if (attackComponent->type & ATTACK_OVERRIDE_COLLISION) { return false; } } return true; } static void updateSprite(EntityDestructibleTile * self) { self->spriteComponent.spriteID = self->destroyed ? SPRITE_ID_WALL_DESTROYED : SPRITE_ID_WALL_CRUMBLY; } static void initComponents(EntityDestructibleTile * self, Vector2i position) { stemobject_assign_vtable(self->positionComponent, EntityComponent_position); stemobject_assign_vtable(self->spriteComponent, EntityComponent_sprite); stemobject_assign_vtable(self->collidableComponent, EntityComponent_collidable); EntityComponent_position_init(&self->positionComponent, position); EntityComponent_sprite_init(&self->spriteComponent, SPRITE_ID_WALL_CRUMBLY, DRAW_LAYER_WALL, 0); EntityComponent_collidable_init(&self->collidableComponent, collisionCallback, self); } bool EntityDestructibleTile_init(EntityDestructibleTile * self, Vector2i position, bool destroyed, struct RoomState * roomState) { call_super(init, self, roomState); self->destroyed = destroyed; initComponents(self, position); updateSprite(self); return true; } EntityDestructibleTile * EntityDestructibleTile_createWithEncodedState(struct memreadContext * memreadContext, struct RoomState * roomState) { GameEntity_createWithEncodedState_implementation(); } void EntityDestructibleTile_initWithEncodedState(EntityDestructibleTile * self, struct memreadContext * memreadContext, struct RoomState * roomState) { initComponents(self, VECTOR2i_ZERO); call_super_virtual(initWithEncodedState, self, memreadContext, roomState); self->positionComponent.lastPosition = self->positionComponent.position; updateSprite(self); } EntityDestructibleTile * EntityDestructibleTile_copy(EntityDestructibleTile * self, struct RoomState * roomState) { stemobject_copy_implementation(initCopy, roomState) } void EntityDestructibleTile_initCopy(EntityDestructibleTile * self, compat_type(EntityDestructibleTile *) originalUntyped, struct RoomState * roomState) { call_super_virtual(initCopy, self, originalUntyped, roomState); EntityDestructibleTile * original = originalUntyped; self->destroyed = original->destroyed; initComponents(self, original->positionComponent.position); call_virtual(initCopy, &self->positionComponent, &original->positionComponent); call_virtual(initCopy, &self->spriteComponent, &original->spriteComponent); call_virtual(initCopy, &self->collidableComponent, &original->collidableComponent); self->collidableComponent.callbackContext = self; updateSprite(self); } void EntityDestructibleTile_dispose(EntityDestructibleTile * self) { call_super_virtual(dispose, self); } compat_type(GameEntityComponent *) EntityDestructibleTile_getComponent(EntityDestructibleTile * self, ComponentType type) { switch (type) { case COMPONENT_COLLIDABLE: if (!self->destroyed) { return &self->collidableComponent; } break; case COMPONENT_POSITION: return &self->positionComponent; case COMPONENT_SPRITE: return &self->spriteComponent; default: break; } return NULL; } bool EntityDestructibleTile_isEqual(EntityDestructibleTile * self, EntityDestructibleTile * compare) { return self->destroyed == compare->destroyed; } void EntityDestructibleTile_enumerateProperties(EntityDestructibleTile * self, bool transient, GameEntity_enumeratePropertiesCallback callback, void * context) { call_super_virtual(enumerateProperties, self, transient, callback, context); if (!transient) { callback(&self->positionComponent.position, PROPERTY_TYPE_Vector2i_int8_t, context); } callback(&self->destroyed, PROPERTY_TYPE_bool, context); } void EntityDestructibleTile_undoActionPerformed(EntityDestructibleTile * self) { updateSprite(self); }