// Copyright (c) 2023 Alex Diener. All rights reserved. #include "PROJECT_NAME/EntityComponent_collidable.h" #include "PROJECT_NAME/EntityComponent_pushable.h" #include "PROJECT_NAME/GameEntity.h" #include "PROJECT_NAME/Utilities.h" #include #define stemobject_implementation EntityComponent_pushable stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(initCopy); stemobject_vtable_entry(update); stemobject_vtable_entry(push); stemobject_vtable_end(); EntityComponent_pushable * EntityComponent_pushable_create(bool multipush) { stemobject_create_implementation(init, multipush) } bool EntityComponent_pushable_init(EntityComponent_pushable * self, bool multipush) { call_super(init, self); self->multipush = multipush; self->pushed = false; return true; } void EntityComponent_pushable_dispose(EntityComponent_pushable * self) { call_super_virtual(dispose, self); } void EntityComponent_pushable_initCopy(EntityComponent_pushable * self, compat_type(GameEntityComponent *) originalUntyped) { call_super_virtual(initCopy, self, originalUntyped); EntityComponent_pushable * original = originalUntyped; self->multipush = original->multipush; self->pushed = original->pushed; } void EntityComponent_pushable_update(EntityComponent_pushable * self, struct GameEntity * entity) { self->pushed = false; } bool EntityComponent_pushable_push(EntityComponent_pushable * self, struct GameEntity * entity, struct GameEntity * pushingEntity, Vector2i direction) { EntityComponent_position * positionComponent = call_virtual(getComponent, entity, COMPONENT_POSITION); assert(positionComponent != NULL); Vector2i newPosition = Vector2i_add(positionComponent->position, direction); if (!self->multipush) { if (isMoveBlockedAtPosition(entity->roomState, newPosition)) { return false; } } else { bool blocked = false; TilePropertyBits tileProperties = RoomState_getTilePropertiesAtPosition(entity->roomState, newPosition); if ((tileProperties & TILE_STATIC_WALL) || !(tileProperties & TILE_STATIC_FLOOR)) { blocked = true; } unsigned int entityCount = RoomState_getEntityCountAtPosition(entity->roomState, newPosition); // Pushing may affect entities at target position; need to list all before mutating GameEntity * entities[entityCount]; for (unsigned int entityIndex = 0; entityIndex < entityCount; entityIndex++) { entities[entityIndex] = RoomState_getEntityAtPositionAtIndex(entity->roomState, newPosition, entityIndex); } for (unsigned int entityIndex = 0; entityIndex < entityCount; entityIndex++) { GameEntity * blockingEntity = entities[entityIndex]; if (!blockingEntity->markedForRemoval) { EntityComponent_collidable * collidableComponent = call_virtual(getComponent, blockingEntity, COMPONENT_COLLIDABLE); if (collidableComponent != NULL && call_virtual(collision, collidableComponent, entity, direction)) { EntityComponent_pushable * pushableComponent = call_virtual(getComponent, blockingEntity, COMPONENT_PUSHABLE); if (pushableComponent == NULL || !call_virtual(push, pushableComponent, blockingEntity, entity, direction)) { blocked = true; } } } } if (blocked) { positionComponent->lastBumpDirection = direction; return false; } } call_virtual(moveTo, positionComponent, newPosition); self->pushed = true; return true; }