/* Make doors */ static void project_feature_handler_MAKE_DOOR(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Require a grid without monsters */ if (square_monster(cave, y, x)) return; /* Require a floor grid */ if (!square_isfloor(cave, y, x)) return; /* Push objects off the grid */ if (square_object(cave, y, x)) push_object(y,x); /* Create closed door */ square_add_door(cave, y, x, true); /* Observe */ if (square_isknown(cave, y, x)) context->obvious = true; /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); }
/** * This will push objects off a square. * * The methodology is to load all objects on the square into a queue. Replace * the previous square with a type that does not allow for objects. Drop the * objects. Last, put the square back to its original type. */ void push_object(int y, int x) { /* Save the original terrain feature */ struct feature *feat_old = square_feat(cave, y, x); struct object *obj = square_object(cave, y, x); struct queue *queue = q_new(z_info->floor_size); bool glyph = square_iswarded(cave, y, x); /* Push all objects on the square, stripped of pile info, into the queue */ while (obj) { struct object *next = obj->next; q_push_ptr(queue, obj); /* Orphan the object */ obj->next = NULL; obj->prev = NULL; obj->iy = 0; obj->ix = 0; /* Next object */ obj = next; } /* Disassociate the objects from the square */ cave->squares[y][x].obj = NULL; /* Set feature to an open door */ square_force_floor(cave, y, x); square_add_door(cave, y, x, false); /* Drop objects back onto the floor */ while (q_len(queue) > 0) { /* Take object from the queue */ obj = q_pop_ptr(queue); /* Drop the object */ drop_near(cave, &obj, 0, y, x, false); } /* Reset cave feature and rune if needed */ square_set_feat(cave, y, x, feat_old->fidx); if (glyph) square_add_ward(cave, y, x); q_free(queue); }