Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarFallingBlocksAgent.cpp
blob: bb9dd84aeee2b2d4205a3d0067e89edcdd08e688 (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
#include "StarFallingBlocksAgent.hpp"
#include "StarRoot.hpp"
#include "StarAssets.hpp"

namespace Star {

FallingBlocksAgent::FallingBlocksAgent(FallingBlocksFacadePtr worldFacade)
  : m_facade(std::move(worldFacade)) {
  m_immediateUpwardPropagateProbability = Root::singleton().assets()->json("/worldserver.config:fallingBlocksImmediateUpwardPropogateProbability").toFloat();
}

void FallingBlocksAgent::update() {
  HashSet<Vec2I> processing = take(m_pending);

  while (!processing.empty()) {
    List<Vec2I> positions;
    for (auto const& pos : take(processing))
      positions.append(pos);

    m_random.shuffle(positions);

    positions.sort([](auto const& a, auto const& b) {
        return a[1] < b[1];
      });

    for (auto const& pos : positions) {
      Vec2I belowPos = pos + Vec2I(0, -1);
      Vec2I belowLeftPos = pos + Vec2I(-1, -1);
      Vec2I belowRightPos = pos + Vec2I(1, -1);

      FallingBlockType thisBlock = m_facade->blockType(pos);
      FallingBlockType belowBlock = m_facade->blockType(belowPos);

      Maybe<Vec2I> moveTo;

      if (thisBlock == FallingBlockType::Falling) {
        if (belowBlock == FallingBlockType::Open)
          moveTo = belowPos;
      } else if (thisBlock == FallingBlockType::Cascading) {
        if (belowBlock == FallingBlockType::Open) {
          moveTo = belowPos;
        } else {
          FallingBlockType belowLeftBlock = m_facade->blockType(belowLeftPos);
          FallingBlockType belowRightBlock = m_facade->blockType(belowRightPos);

          if (belowLeftBlock == FallingBlockType::Open && belowRightBlock == FallingBlockType::Open)
            moveTo = m_random.randb() ? belowLeftPos : belowRightPos;
          else if (belowLeftBlock == FallingBlockType::Open)
            moveTo = belowLeftPos;
          else if (belowRightBlock == FallingBlockType::Open)
            moveTo = belowRightPos;
        }
      }

      if (moveTo) {
        m_facade->moveBlock(pos, *moveTo);
        if (m_random.randf() < m_immediateUpwardPropagateProbability) {
          processing.add(pos + Vec2I(0, 1));
          processing.add(pos + Vec2I(-1, 1));
          processing.add(pos + Vec2I(1, 1));
        }

        visitLocation(pos);
        visitLocation(*moveTo);
      }
    }
  }
}

void FallingBlocksAgent::visitLocation(Vec2I const& location) {
  visitRegion(RectI::withSize(location, Vec2I(1, 1)));
}

void FallingBlocksAgent::visitRegion(RectI const& region) {
  for (int x = region.xMin() - 1; x <= region.xMax(); ++x) {
    for (int y = region.yMin(); y <= region.yMax(); ++y) 
      m_pending.add({x, y});
  }
}

}