Shofel2_T124_python/venv/lib/python3.10/site-packages/asciimatics/renderers/fire.py

152 lines
5.3 KiB
Python
Raw Normal View History

2024-05-25 16:45:07 +00:00
# -*- coding: utf-8 -*-
"""
This module implements a fire effect renderer.
"""
from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
from builtins import range
import copy
from random import randint, random
from asciimatics.renderers.base import DynamicRenderer
from asciimatics.screen import Screen
class Fire(DynamicRenderer):
"""
Renderer to create a fire effect based on a specified `emitter` that
defines the heat source.
The implementation here uses the same techniques described in
http://freespace.virgin.net/hugo.elias/models/m_fire.htm, although a
slightly different implementation.
"""
_COLOURS_16 = [
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, 0),
(Screen.COLOUR_RED, Screen.A_BOLD),
(Screen.COLOUR_RED, Screen.A_BOLD),
(Screen.COLOUR_RED, Screen.A_BOLD),
(Screen.COLOUR_RED, Screen.A_BOLD),
(Screen.COLOUR_YELLOW, Screen.A_BOLD),
(Screen.COLOUR_YELLOW, Screen.A_BOLD),
(Screen.COLOUR_YELLOW, Screen.A_BOLD),
(Screen.COLOUR_YELLOW, Screen.A_BOLD),
(Screen.COLOUR_WHITE, Screen.A_BOLD),
]
_COLOURS_256 = [
(0, 0),
(52, 0),
(88, 0),
(124, 0),
(160, 0),
(196, 0),
(202, 0),
(208, 0),
(214, 0),
(220, 0),
(226, 0),
(227, 0),
(228, 0),
(229, 0),
(230, 0),
(231, 0),
]
_CHARS = " ...::$$$&&&@@"
def __init__(self, height, width, emitter, intensity, spot, colours,
bg=False):
"""
:param height: Height of the box to contain the flames.
:param width: Width of the box to contain the flames.
:param emitter: Heat source for the flames. Any non-whitespace
character is treated as part of the heat source.
:param intensity: The strength of the flames. The bigger the number,
the hotter the fire. 0 <= intensity <= 1.0.
:param spot: Heat of each spot source. Must be an integer > 0.
:param colours: Number of colours the screen supports.
:param bg: (Optional) Whether to render background colours only.
"""
super(Fire, self).__init__(height, width)
self._emitter = emitter
self._intensity = intensity
self._spot_heat = spot
self._count = len([c for c in emitter if c not in " \n"])
line = [0 for _ in range(self._canvas.width)]
self._buffer = [copy.deepcopy(line) for _ in range(self._canvas.width * 2)]
self._colours = self._COLOURS_256 if colours >= 256 else \
self._COLOURS_16
self._bg_too = bg
# Figure out offset of emitter to centre at the bottom of the buffer
e_width = 0
e_height = 0
for line in self._emitter.split("\n"):
e_width = max(e_width, len(line))
e_height += 1
self._x = (width - e_width) // 2
self._y = height - e_height
def _render_now(self):
# First make the fire rise with convection
for y in range(len(self._buffer) - 1):
self._buffer[y] = self._buffer[y + 1]
self._buffer[len(self._buffer) - 1] = [0 for _ in range(self._canvas.width)]
# Seed new hot spots
x = self._x
y = self._y
for c in self._emitter:
if c not in " \n" and random() < self._intensity:
self._buffer[y][x] += randint(1, self._spot_heat)
if c == "\n":
x = self._x
y += 1
else:
x += 1
# Seed a few cooler spots
for _ in range(self._canvas.width // 2):
self._buffer[randint(0, self._canvas.height - 1)][
randint(0, self._canvas.width - 1)] -= 10
# Simulate cooling effect of the resulting environment.
for y in range(len(self._buffer)):
for x in range(self._canvas.width):
new_val = self._buffer[y][x]
if y < len(self._buffer) - 1:
new_val += self._buffer[y + 1][x]
if x > 0:
new_val += self._buffer[y][x - 1]
if x < self._canvas.width - 1:
new_val += self._buffer[y][x + 1]
self._buffer[y][x] = new_val // 4
# Now build the rendered text from the simulated flames.
self._clear()
for x in range(self._canvas.width):
for y in range(len(self._buffer)):
if self._buffer[y][x] > 0:
colour = self._colours[min(len(self._colours) - 1,
self._buffer[y][x])]
if self._bg_too:
char = " "
bg = colour[0]
else:
char = self._CHARS[min(len(self._CHARS) - 1,
self._buffer[y][x])]
bg = 0
self._write(char, x, y, colour[0], colour[1], bg)
return self._plain_image, self._colour_map