Chaotic & Dice
Chaotic Chaotic
Слушай, Дима, а не думал превратить свой настольный хаос в код? Давай сделаем rogue-like, где каждый удар, заклинание и сюжетный поворот будет зависеть от кучи кубиков — ты бросаешь, я пишу. Давай оживим эту непредсказуемость.
Dice Dice
Отлично, давай! Ты взломай код, я брошу кости, и посмотрим, что за хаос выйдет — каждый удар, заклинание, поворот сюжета будет сюрпризом. Принеси сценарии, я принесу азарта. Вперёд!
Chaotic Chaotic
Вот набросок на Python, чтобы тебе было проще начать. Тебе понадобится Python 3.12 или выше, чтобы использовать встроенный модуль `random` и немного `dataclasses` для ясности. ```python #!/usr/bin/env python3 # dice_rogue.py import random from dataclasses import dataclass, field # --------- Dice utilities --------- def roll(dice: int = 1, sides: int = 6) -> int: """Roll `dice` number of `sides`‑sided dice and sum.""" return sum(random.randint(1, sides) for _ in range(dice)) # --------- Combat system --------- @dataclass class Character: name: str hp: int attack: int = field(default=1) defense: int = field(default=0) dice: int = field(default=1) # how many dice the character rolls for damage def is_alive(self) -> bool: return self.hp > 0 def damage_roll(self) -> int: return roll(self.dice, 6) + self.attack def take_damage(self, dmg: int): dmg -= self.defense dmg = max(0, dmg) self.hp -= dmg print(f"{self.name} получает {dmg} урона (осталось HP: {self.hp})") # --------- Example encounter --------- def encounter(attacker: Character, defender: Character): if not (attacker.is_alive() and defender.is_alive()): return dmg = attacker.damage_roll() print(f"{attacker.name} атакует {defender.name} с броском {dmg} (без учета защиты)") defender.take_damage(dmg) # --------- Main game loop --------- def main(): hero = Character(name="Hero", hp=30, attack=2, defense=1, dice=2) monster = Character(name="Goblin", hp=15, attack=1, defense=0, dice=1) round_counter = 1 while hero.is_alive() and monster.is_alive(): print(f"\n--- Раунд {round_counter} ---") # Hero goes first encounter(hero, monster) if not monster.is_alive(): print("Гоблин повержен! Ты победил.") break # Monster counterattacks encounter(monster, hero) if not hero.is_alive(): print("Герой пал! Игра окончена.") break round_counter += 1 if __name__ == "__main__": main() ``` ### Как играть 1. **Сохрани** код в файл `dice_rogue.py`. 2. **Запусти** его командой `python dice_rogue.py`. 3. Скрипт будет выводить каждый раунд, броски кубиков и наносимый урон. 4. Чтобы добавить хаоса, измени параметры `dice`, `attack`, `defense` или параметр `sides` в функции `roll()`. Не стесняйся добавлять больше заклинаний, предметов или даже таблицу добычи — просто пусть кубики катятся и дай волю дикости! Приятного кодинга!
Dice Dice
Крутая раскладка, братан! Это чистый хаос, основанный на бросках кубиков – прямо то, что надо. Как насчет добавления какого-нибудь безумного правила "крита"? Типа, если выкидываешь шесть на каждом кубике, удваиваешь урон или получаешь бонус к перемещению. Или добавить систему слотов заклинаний, где каждое заклинание стоит разное количество кубиков. Держи случайность на высоте и смотри, как истории срываются с цепи! Бросай кости!
Chaotic Chaotic
Давай устроим полный хаос. Добавляем флаг "критический": `crit = all(d == 6 for d in rolled_dice)` Если крит – удваиваем общий урон и даём свободное действие (например, быстрый уход или дополнительная атака в следующем ходу). Для заклинаний давайте каждому стоимость в кубиках: Огненный шар – 3 кубика, Лечение – 2 кубика, Телепорт – 1 кубик. Игрок отслеживает, сколько кубиков он может бросить в этот раунд; он тратит их на заклинания или атаки. Если кубики закончились – вынужден отдохнуть (или просто бросает максимальное количество оставшихся кубиков). Это поддерживает случайность и закручивает сюжет. Бросай!
Dice Dice
Конечно! Вот патч – держи, не теряй и не скучай. Сначала подправь вспомогательную функцию для броска, чтобы она возвращала необработанные кубики, чтобы мы могли проверять критические удары: def roll(dice: int = 1, sides: int = 6): rolls = [random.randint(1, sides) for _ in range(dice)] return sum(rolls), rolls Теперь у Персонажа есть пул кубиков на раунд, флаг для свободного действия и гримуар: @dataclass class Character: name: str hp: int attack: int = field(default=1) defense: int = field(default=0) dice: int = field(default=2) # пул для этого раунда free_action: bool = field(default=False) spellbook: dict = field(default_factory=lambda: { 'Fireball': 3, 'Heal': 2, 'Blink': 1 }) def is_alive(self) -> bool: return self.hp > 0 def damage_roll(self, dice_used: int) -> int: total, rolls = roll(dice_used, 6) crit = all(r == 6 for r in rolls) dmg = total + self.attack if crit: dmg *= 2 self.free_action = True return dmg def take_damage(self, dmg: int): dmg -= self.defense dmg = max(0, dmg) self.hp -= dmg print(f"{self.name} получает {dmg} урона (осталось HP: {self.hp})") def spend_dice(self, cost: int) -> bool: if self.dice >= cost: self.dice -= cost return True return False Теперь вставляем это в цикл: def encounter(attacker: Character, defender: Character): if not (attacker.is_alive() and defender.is_alive()): return # Атака использует 1 кубик, если свободное действие позволяет использовать 2 dice_used = 2 if attacker.free_action else 1 dmg = attacker.damage_roll(dice_used) print(f"{attacker.name} атакует {defender.name} с броском {dmg} (исходный)") defender.take_damage(dmg) # Если у нападающего есть свободное действие, сбрасываем его после использования if attacker.free_action: attacker.free_action = False # Пример заклинания – герой использует Огненный шар, если это возможно def cast_spell(caster: Character, target: Character, spell: str): cost = caster.spellbook.get(spell) if cost and caster.spend_dice(cost): print(f"{caster.name} произносит заклинание {spell}, затрачивая {cost} кубика!") if spell == 'Fireball': dmg = caster.damage_roll(cost) # используем все кубики для огненного шара target.take_damage(dmg) elif spell == 'Heal': heal = 10 # произвольное количество исцеления caster.hp += heal print(f"{caster.name} исцеляется на {heal} HP (теперь {caster.hp})") elif spell == 'Blink': print(f"{caster.name} исчезает из поля зрения – без урона, но продолжает движение") else: print(f"{caster.name} не может позволить себе {spell} – требуется {cost} кубика.") Наконец, в основном цикле можно сбрасывать пул кубиков каждый раунд и решать, стоит ли использовать заклинание: while hero.is_alive() and monster.is_alive(): print(f"\n--- Раунд {round_counter} ---") hero.dice = 2 # сброс пула в начале раунда monster.dice = 1 # Герой может выбрать заклинание или обычную атаку if hero.dice >= hero.spellbook['Fireball'] and not hero.free_action: cast_spell(hero, monster, 'Fireball') else: encounter(hero, monster) # Монстр контратакует if monster.is_alive(): encounter(monster, hero) Это двигатель хаоса – каждый кубик бросается, криты удваивают урон, свободные действия дают дополнительный удар или уклонение, и тебе приходится экономить кубики или отдыхать (можно добавить отдых, который восстанавливает пул). Экспериментируй, подкручивай числа и наблюдай, как настолка оживает в коде. Бросай кости!
Chaotic Chaotic
Отличная доработка, братан! Теперь каждый бросок – потенциальная бомба замедления. Может, добавь ещё кубик "хамелеон", который может перевернуть всю раунд – единица означает потерю одного кубика в следующем ходу, а шестёрка даёт дополнительное действие в следующий ход. Или сделай так, чтобы заклинание "Блик" реально перемещало цель на крошечной сетке, чтобы следующая атака могла провалиться. Продолжай менять состав кубиков, и сюжет будет постоянно удивлять. Бросай кости!
Dice Dice
Добавь в пул броска нестандартный кубик. Когда бросаешь, проверяй, выпало ли на каком-нибудь кубике 1 или 6 – это и будет нестандартный кубик. ```python def roll(dice:int=1,sides:int=6): rolls=[random.randint(1,sides) for _ in range(dice)] total=sum(rolls) # логика нестандартного кубика if 1 in rolls: # теряешь кубик в следующем ходе return total, rolls, {'lose':1} if 6 in rolls: # бесплатное действие в следующем раунде return total, rolls, {'free':1} return total, rolls, {} ``` Теперь у каждого персонажа создай небольшую сетку: ```python @dataclass class Character: ... x:int=0 y:int=0 ``` Заклинание "Мгновение" перемещает цель на одну клетку в случайном направлении: ```python def cast_spell(caster:Character,target:Character,spell:str): cost=caster.spellbook.get(spell) if not caster.spend_dice(cost): return if spell=='Blink': dir=random.choice([(1,0),(-1,0),(0,1),(0,-1)]) target.x+=dir[0] target.y+=dir[1] print(f"{target.name} мгновенно перемещается в ({target.x},{target.y})") ``` Во время столкновения, после нанесения урона, применяй эффекты нестандартного кубика: `total, rolls, effect = roll(dice_used,6)` `dmg = total + attacker.attack` `if effect.get('lose'):` `attacker.dice = max(0, attacker.dice-1)` `print(f"{attacker.name} теряет кубик в следующем раунде")` `if effect.get('free'):` `attacker.free_action = True` `print(f"{attacker.name} получает бесплатное действие в следующем раунде")` Также корректируй шанс попадания в зависимости от расстояния: ```python def hit_chance(attacker,defender): dist=abs(attacker.x-defender.x)+abs(attacker.y-defender.y) return max(0.2, 1-0.1*dist) ``` Если расстояние больше нуля, снижай шанс попадания, чтобы "Мгновение" могло помочь уклониться от удара. Теперь твой пул кубиков – живое существо, нестандартный кубик может переломить ход битвы, а "Мгновение" демонстрирует визуальное изменение сетки. Бросай кубики и пусть хаос продолжает кружиться!
Chaotic Chaotic
Круто, этот вайлд-кард заставляет каждую партию ощущаться как игра в рулетку. Может, добавим что-то вроде "критическое" событие, которое срабатывает только при выпадении двойной шестерки, или пусть Блинк тоже даёт временной щит при переходе на новую клетку. Держи поле небольшим, бросай кости и смотри, как начинается хаос!