"""Consumables redesign: remove shield/reroll, add wild_card/lucky_dice/copycat/undo Revision ID: 027_consumables_redesign Revises: 026_update_boost_desc Create Date: 2026-01-08 """ from typing import Sequence, Union from datetime import datetime from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = '027_consumables_redesign' down_revision: Union[str, None] = '026_update_boost_desc' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # 1. Remove has_shield column from participants op.drop_column('participants', 'has_shield') # 2. Add new columns for lucky_dice and undo op.add_column('participants', sa.Column('has_lucky_dice', sa.Boolean(), nullable=False, server_default='false')) op.add_column('participants', sa.Column('lucky_dice_multiplier', sa.Float(), nullable=True)) op.add_column('participants', sa.Column('last_drop_points', sa.Integer(), nullable=True)) op.add_column('participants', sa.Column('last_drop_streak_before', sa.Integer(), nullable=True)) op.add_column('participants', sa.Column('can_undo', sa.Boolean(), nullable=False, server_default='false')) # 3. Remove old consumables from shop op.execute("DELETE FROM shop_items WHERE code IN ('reroll', 'shield')") # 4. Update boost price from 200 to 150 op.execute("UPDATE shop_items SET price = 150 WHERE code = 'boost'") # 5. Add new consumables to shop now = datetime.utcnow().isoformat() op.execute(f""" INSERT INTO shop_items (item_type, code, name, description, price, rarity, asset_data, is_active, created_at) VALUES ('consumable', 'wild_card', 'Дикая карта', 'Выбери игру и получи случайное задание из неё', 150, 'uncommon', '{{"effect": "wild_card", "icon": "shuffle"}}', true, '{now}'), ('consumable', 'lucky_dice', 'Счастливые кости', 'Случайный множитель очков (1.5x - 4.0x)', 250, 'rare', '{{"effect": "lucky_dice", "multipliers": [1.5, 2.0, 2.5, 3.0, 3.5, 4.0], "icon": "dice"}}', true, '{now}'), ('consumable', 'copycat', 'Копикэт', 'Скопируй задание любого участника марафона', 300, 'epic', '{{"effect": "copycat", "icon": "copy"}}', true, '{now}'), ('consumable', 'undo', 'Отмена', 'Отмени последний дроп и верни очки со стриком', 300, 'epic', '{{"effect": "undo", "icon": "undo"}}', true, '{now}') """) def downgrade() -> None: # 1. Remove new columns op.drop_column('participants', 'can_undo') op.drop_column('participants', 'last_drop_streak_before') op.drop_column('participants', 'last_drop_points') op.drop_column('participants', 'lucky_dice_multiplier') op.drop_column('participants', 'has_lucky_dice') # 2. Add back has_shield op.add_column('participants', sa.Column('has_shield', sa.Boolean(), nullable=False, server_default='false')) # 3. Remove new consumables op.execute("DELETE FROM shop_items WHERE code IN ('wild_card', 'lucky_dice', 'copycat', 'undo')") # 4. Restore boost price back to 200 op.execute("UPDATE shop_items SET price = 200 WHERE code = 'boost'") # 5. Add back old consumables now = datetime.utcnow().isoformat() op.execute(f""" INSERT INTO shop_items (item_type, code, name, description, price, rarity, asset_data, is_active, created_at) VALUES ('consumable', 'shield', 'Щит', 'Защита от штрафа при следующем дропе. Streak сохраняется.', 150, 'uncommon', '{{"effect": "shield", "icon": "shield"}}', true, '{now}'), ('consumable', 'reroll', 'Перекрут', 'Перекрутить колесо и получить новое задание', 80, 'common', '{{"effect": "reroll", "icon": "refresh-cw"}}', true, '{now}') """)