DEADSOFTWARE

99d1a046b51605b9e8570e408e69b4eb5105cbe8
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / world / GameWorldFluidsLogicControllerTask.java
1 package ru.deadsoftware.cavedroid.game.world;
3 import com.badlogic.gdx.utils.Timer;
4 import ru.deadsoftware.cavedroid.game.GameItemsHolder;
5 import ru.deadsoftware.cavedroid.game.GameScope;
6 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
7 import ru.deadsoftware.cavedroid.game.model.block.Block;
9 import javax.annotation.CheckForNull;
10 import javax.inject.Inject;
11 import java.util.*;
13 @GameScope
14 public class GameWorldFluidsLogicControllerTask extends Timer.Task {
16 public static final float FLUID_UPDATE_INTERVAL_SEC = 0.1f;
18 private final GameWorld mGameWorld;
19 private final MobsController mMobsController;
20 private final GameItemsHolder mGameItemsHolder;
22 private final Map<Class<? extends Block.Fluid>, List<? extends Block.Fluid>> mFluidStatesMap;
24 @Inject
25 GameWorldFluidsLogicControllerTask(GameWorld gameWorld,
26 MobsController mobsController,
27 GameItemsHolder gameItemsHolder) {
28 mGameWorld = gameWorld;
29 mMobsController = mobsController;
30 mGameItemsHolder = gameItemsHolder;
32 final List<Block.Water> waters = mGameItemsHolder.getBlocksByType(Block.Water.class);
33 waters.sort(Comparator.comparingInt(Block.Water::getState));
35 final List<Block.Lava> lavas = mGameItemsHolder.getBlocksByType(Block.Lava.class);
36 lavas.sort(Comparator.comparingInt(Block.Lava::getState));
38 mFluidStatesMap = new HashMap<>();
39 mFluidStatesMap.put(Block.Water.class, waters);
40 mFluidStatesMap.put(Block.Lava.class, lavas);
41 }
43 @CheckForNull
44 private List<? extends Block.Fluid> getFluidStateList(Block.Fluid fluid) {
45 return mFluidStatesMap.get(fluid.getClass());
46 }
48 private int getCurrentStateIndex(Block.Fluid fluid) {
49 @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
51 if (stateList == null) {
52 return -1;
53 }
55 return stateList.indexOf(fluid);
56 }
58 @CheckForNull
59 private Block.Fluid getNextStateBlock(Block.Fluid fluid) {
60 @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
62 if (stateList == null) {
63 return null;
64 }
66 int currentState = stateList.indexOf(fluid);
68 if (currentState < 0) {
69 return null;
70 }
72 int nextState = currentState + 1;
74 if (nextState == 1) {
75 nextState++;
76 }
78 if (nextState < stateList.size()) {
79 return stateList.get(nextState);
80 }
82 return null;
83 }
85 private boolean noFluidNearby(int x, int y) {
86 return !mGameWorld.getForeMap(x, y - 1).isFluid() &&
87 (!mGameWorld.getForeMap(x - 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x - 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()) &&
88 (!mGameWorld.getForeMap(x + 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x + 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState());
89 }
91 private boolean drainFluid(int x, int y) {
92 final Block block = mGameWorld.getForeMap(x, y);
94 if (!(block instanceof Block.Fluid fluid)) {
95 return true;
96 }
98 if (fluid.getState() > 0) {
99 if (noFluidNearby(x, y)) {
100 @CheckForNull final Block nextState = getNextStateBlock(fluid);
101 if (nextState == null) {
102 mGameWorld.resetForeMap(x, y);
103 return true;
106 mGameWorld.setForeMap(x, y, nextState);
109 return false;
112 private boolean fluidCanFlowThere(Block.Fluid fluid, Block targetBlock) {
113 return targetBlock == mGameItemsHolder.getFallbackBlock() ||
114 (!targetBlock.getParams().getHasCollision() && !targetBlock.isFluid()) ||
115 (fluid.getClass() == targetBlock.getClass() && fluid.getState() < ((Block.Fluid)targetBlock).getState());
118 private void flowFluidTo(Block.Fluid currentFluid, int x, int y, Block.Fluid nextStateFluid) {
119 final Block targetBlock = mGameWorld.getForeMap(x, y);
121 if (fluidCanFlowThere(currentFluid, targetBlock)) {
122 mGameWorld.setForeMap(x, y, nextStateFluid);
123 } else if (currentFluid.isWater() && targetBlock.isLava()) {
124 if (((Block.Lava)targetBlock).getState() > 0) {
125 mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("cobblestone"));
126 } else {
127 mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("obsidian"));
129 } else if (currentFluid.isLava() && targetBlock.isWater()) {
130 mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("stone"));
134 private void flowFluid(int x, int y) {
135 Block.Fluid fluid = (Block.Fluid) mGameWorld.getForeMap(x, y);
136 @CheckForNull final List<? extends Block.Fluid> stateList = getFluidStateList(fluid);
138 if (stateList == null) {
139 return;
142 if (fluid.getState() < stateList.size() - 1 && mGameWorld.getForeMap(x, y + 1).hasCollision()) {
143 @CheckForNull Block.Fluid nextState = getNextStateBlock(fluid);
145 if (nextState == null) {
146 return;
149 flowFluidTo(fluid, x - 1, y, nextState);
150 flowFluidTo(fluid, x + 1, y, nextState);
151 } else {
152 flowFluidTo(fluid, x, y + 1, stateList.get(1));
157 private void updateFluids(int x, int y) {
158 if (!mGameWorld.getForeMap(x, y).isFluid()) {
159 return;
161 if (drainFluid(x, y)) {
162 return;
164 flowFluid(x, y);
167 private void fluidUpdater() {
168 int midScreen = (int) mMobsController.getPlayer().x / 16;
169 for (int y = mGameWorld.getHeight() - 1; y >= 0; y--) {
170 for (int x = 0; x <= Math.min(mGameWorld.getWidth() / 2, 32); x++) {
171 updateFluids(midScreen + x, y);
172 updateFluids(midScreen - x, y);
177 @Override
178 public void run() {
179 fluidUpdater();