summaryrefslogtreecommitdiff
path: root/src/sliceitoff/field/field.py
blob: 27f4cebf44120fb459a98ac976fa6ffc1b1a476f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
""" field.field - The playing area or slices, lazer of explosions of it """
import os
from random import randrange, choice

import pygame

from display import Scaling, CGA_COLORS
from text import LetterSprite

DEBUG = os.getenv("DEBUG")

class FieldSprite(pygame.sprite.Sprite):
    """ Playing area consist of these sprites """
    def __init__(self, area: tuple):
        super().__init__()
        self.color = (0,255,0,255)
        self.dead = False
        self.area = area
        self.rect = Scaling.area_to_rect(self.area)
        self.image = pygame.Surface(self.rect.size)
        self.image.fill(self.color)

class SliceSprite(FieldSprite):
    """ Flashing rectangle like lazer """
    def __init__(self, area: tuple ):
        super().__init__(area)
        self.color = (255,255,255,255)
        self.image.fill(self.color)
        self.timeout = 300
        self.dead = True

    def update(self, dt = 0, **kwargs):
        """ Just pick a randon color every update from cga palette """
        # pylint: disable = unused-argument
        # explosion arg is given, but no use in SliceSprite
        if dt:
            self.timeout -= dt
            self.color = choice(CGA_COLORS)
            if self.timeout <= 0:
                self.kill()
            else:
                self.image.fill(self.color)


class Field(pygame.sprite.LayeredUpdates):
    """ group that contains all pieces of field """
    initial_area = (320_000, 220_000)

    def __init__(self, stats = None):
        super().__init__()
        self.add(FieldSprite( (0, 0, *__class__.initial_area) ))
        self.area_full = __class__.initial_area[0] * __class__.initial_area[1]
        self.stats = stats

    def calculate_current_area(self):
        """ calculates sum of areas of all fields """
        return sum( s.area[2]*s.area[3] for s in self.active_sprites() )

    def update(self, **kwargs):
        """ just force explosion on """
        super().update(explode = True, **kwargs)

    def update_stats(self):
        """ calculates remaining area and remaining percentage """
        self.stats.percent = 100 * self.calculate_current_area() / self.area_full
        if DEBUG:
            print(f"FIELD: {self.stats.percent}")

    def slice(
            self,
            pos: tuple,
            direction: bool,
            thickness: int) -> pygame.Rect:
        """ Slice one area into two areas """

        # Slicing hits the area?
        for overlap in self.get_sprites_at(Scaling.scale_to_display(pos)):
            if not overlap.dead:
                break
        else:
            return None

        # Save the area information and remove the sprite
        overlap_area = overlap.area
        overlap.remove(self)

        slicer = self.vertical_slicer if direction else self.horizontal_slicer
        # create new areas if there is any space
        area = slicer(pos, overlap_area, thickness)
        self.explode(area)
        zap_spite = SliceSprite(area)
        self.add(zap_spite)
        return zap_spite

    def vertical_slicer(self, pos, area, thickness):
        """ slices area in 3 parts vertically. returns lazer area """
        ax, ay, aw, ah = area
        t2 = pos[0] - thickness
        t3 = pos[0] + thickness
        t4 = ax + aw
        if t2 > ax:
            self.add(FieldSprite( (ax, ay, t2-ax, ah) ))
        if t4 > t3:
            self.add(FieldSprite( (t3, ay, t4-t3, ah) ))
        return (t2, ay, t3-t2, ah)

    def horizontal_slicer(self, pos, area, thickness):
        """ slices area in 3 parts horizontally. returns lazer area """
        ax, ay, aw, ah = area
        t2 = pos[1] - thickness
        t3 = pos[1] + thickness
        t4 = ay + ah
        if t2 > ay:
            self.add(FieldSprite( (ax, ay, aw, t2-ay) ))
        if t4 > t3:
            self.add(FieldSprite( (ax, t3, aw, t4-t3) ))
        return (ax, t2, aw, t3-t2)


    def active_sprites(self):
        """ Returns all sprites that are not dead """
        return [s for s in self.sprites() if not s.dead]

    def active_rects(self):
        """ Returns active areas as rects """
        return [s.rect for s in self.sprites() if not s.dead]

    def explode(self, area):
        """ Make area full of explogind letters """
        sx, sy, w, h = area
        for x in range(int(sx),int(sx+w),8_000):
            for y in range(int(sy),int(sy+h),8_000):
                self.add(LetterSprite(
                        ('8x8', 8_000, 0xf),
                        randrange(0,0x100),
                        Scaling.scale_to_display((x,y)) ))

    def kill_if_not_colliding(self, sprites):
        """ If there is empty fields that are not yet dead kill them """
        for field in self.active_sprites():
            for enemy in sprites:
                if enemy.rect.colliderect(field.rect):
                    break
            else:
                self.explode(field.area)
                field.remove(self)
        self.stats.field_count = len(self.active_sprites())