DEADSOFTWARE

Add use item actions module
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / GameInput.java
1 package ru.deadsoftware.cavedroid.game;
3 import com.badlogic.gdx.Gdx;
4 import com.badlogic.gdx.Input;
5 import com.badlogic.gdx.graphics.g2d.TextureRegion;
6 import com.badlogic.gdx.math.Intersector;
7 import com.badlogic.gdx.math.MathUtils;
8 import com.badlogic.gdx.utils.TimeUtils;
9 import com.google.common.collect.Range;
10 import ru.deadsoftware.cavedroid.MainConfig;
11 import ru.deadsoftware.cavedroid.game.actions.PlaceBlockActionUtilsKt;
12 import ru.deadsoftware.cavedroid.game.actions.useitem.IUseItemAction;
13 import ru.deadsoftware.cavedroid.game.mobs.Mob;
14 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
15 import ru.deadsoftware.cavedroid.game.mobs.Pig;
16 import ru.deadsoftware.cavedroid.game.mobs.Player;
17 import ru.deadsoftware.cavedroid.game.objects.DropController;
18 import ru.deadsoftware.cavedroid.game.objects.Item;
19 import ru.deadsoftware.cavedroid.game.world.GameWorld;
20 import ru.deadsoftware.cavedroid.misc.Assets;
21 import ru.deadsoftware.cavedroid.misc.ControlMode;
23 import javax.annotation.CheckForNull;
24 import javax.inject.Inject;
26 import java.util.Map;
28 import static ru.deadsoftware.cavedroid.game.GameItems.*;
30 @GameScope
31 public class GameInput {
33 private static final String TAG = "GameInput";
35 private final MainConfig mMainConfig;
36 private final GameWorld mGameWorld;
37 private final DropController mDropController;
38 private final MobsController mMobsController;
39 private final Map<String, IUseItemAction> mUseItemActionMap;
41 private final Player mPlayer;
43 private ControlMode mControlMode;
45 private boolean mKeyDown;
46 private boolean mTouchedDown;
47 private boolean mDragging;
49 private int mKeyDownCode;
50 private int mTouchDownBtn;
51 private float mTouchDownX;
52 private float mTouchDownY;
53 private long mTouchDownTime;
55 private int mCurX;
56 private int mCurY;
57 private int mCreativeScroll;
58 private int mBlockDamage;
60 @Inject
61 public GameInput(MainConfig mainConfig,
62 GameWorld gameWorld,
63 DropController dropController,
64 MobsController mobsController,
65 Map<String, IUseItemAction> useItemActionMap) {
66 mMainConfig = mainConfig;
67 mGameWorld = gameWorld;
68 mDropController = dropController;
69 mMobsController = mobsController;
70 mUseItemActionMap = useItemActionMap;
72 mPlayer = mMobsController.getPlayer();
74 mControlMode = mMainConfig.isTouch() ? ControlMode.WALK : ControlMode.CURSOR;
75 }
77 private boolean checkSwim() {
78 return GameItems.isFluid(mGameWorld.getForeMap(mPlayer.getMapX(), mPlayer.getLowerMapY()));
79 }
81 private void goUpwards() {
82 if (checkSwim()) {
83 mPlayer.swim = true;
84 } else if (mPlayer.canJump()) {
85 mPlayer.jump();
86 } else if (!mPlayer.isFlyMode() && mPlayer.gameMode == 1) {
87 mPlayer.setFlyMode(true);
88 mPlayer.getVelocity().y = 0;
89 } else if (mPlayer.isFlyMode()) {
90 mPlayer.getVelocity().y = -mPlayer.getSpeed();
91 }
92 }
94 @SuppressWarnings("IntegerDivisionInFloatingPointContext")
95 private boolean insideCreativeInv(float screenX, float screenY) {
96 TextureRegion creative = Assets.textureRegions.get("creative");
97 return (screenX > mMainConfig.getWidth() / 2 - creative.getRegionWidth() / 2 &&
98 screenX < mMainConfig.getWidth() / 2 + creative.getRegionWidth() / 2 &&
99 screenY > mMainConfig.getHeight() / 2 - creative.getRegionHeight() / 2 &&
100 screenY < mMainConfig.getHeight() / 2 + creative.getRegionHeight() / 2);
103 private void wasdPressed(int keycode) {
104 if (mControlMode == ControlMode.WALK || !mMainConfig.isTouch()) {
105 switch (keycode) {
106 case Input.Keys.A:
107 mPlayer.getVelocity().x = -mPlayer.getSpeed();
108 mPlayer.setDir(Mob.Direction.LEFT);
109 if (mMainConfig.isTouch() && checkSwim()) {
110 mPlayer.swim = true;
112 break;
113 case Input.Keys.D:
114 mPlayer.getVelocity().x = mPlayer.getSpeed();
115 mPlayer.setDir(Mob.Direction.RIGHT);
116 if (mMainConfig.isTouch() && checkSwim()) {
117 mPlayer.swim = true;
119 break;
120 case Input.Keys.W:
121 case Input.Keys.SPACE:
122 goUpwards();
123 break;
124 case Input.Keys.S:
125 case Input.Keys.CONTROL_LEFT:
126 mPlayer.getVelocity().y = mPlayer.getSpeed();
127 break;
129 } else {
130 switch (keycode) {
131 case Input.Keys.A:
132 mCurX--;
133 break;
134 case Input.Keys.D:
135 mCurX++;
136 break;
137 case Input.Keys.W:
138 mCurY--;
139 break;
140 case Input.Keys.S:
141 mCurY++;
142 break;
144 mBlockDamage = 0;
148 private boolean isNotAutoselectable(int x, int y) {
149 return (!mGameWorld.hasForeAt(x, y) || !mGameWorld.getForeMapBlock(x, y).hasCollision());
152 private void checkCursorBounds() {
153 if (mCurY < 0) {
154 mCurY = 0;
155 } else if (mCurY >= mGameWorld.getHeight()) {
156 mCurY = mGameWorld.getHeight() - 1;
159 if (mControlMode == ControlMode.CURSOR) {
160 if (mCurX * 16 + 8 < mPlayer.getX() + mPlayer.getWidth() / 2) {
161 mPlayer.setDir(Mob.Direction.LEFT);
162 } else {
163 mPlayer.setDir(Mob.Direction.RIGHT);
168 public void moveCursor(GameRenderer gameRenderer) {
169 int pastX = mCurX;
170 int pastY = mCurY;
172 if (mControlMode == ControlMode.WALK && mMainConfig.isTouch()) {
173 mCurX = mPlayer.getMapX() + (mPlayer.looksLeft() ? -1 : 1);
174 mCurY = mPlayer.getUpperMapY();
175 for (int i = 0; i < 2 && isNotAutoselectable(mCurX, mCurY); i++) {
176 mCurY++;
178 if (isNotAutoselectable(mCurX, mCurY)) {
179 mCurX += mPlayer.looksLeft() ? 1 : -1;
181 } else if (!mMainConfig.isTouch()) {
182 final int tmpX = (int) (Gdx.input.getX() * (mMainConfig.getWidth() /
183 Gdx.graphics.getWidth()) + gameRenderer.getCamX());
184 mCurX = tmpX / 16;
186 final int tmpY = (int) (Gdx.input.getY() * (mMainConfig.getHeight() /
187 Gdx.graphics.getHeight()) + gameRenderer.getCamY());
188 mCurY = tmpY / 16;
190 if (tmpX < 0) {
191 mCurX--;
194 final double a = tmpX - mPlayer.x;
195 final double b = tmpY - mPlayer.y;
197 mPlayer.headRotation = (float) Math.atan(b / a) * MathUtils.radDeg;
200 if (pastX != mCurX || pastY != mCurY) {
201 mBlockDamage = 0;
204 checkCursorBounds();
207 private void useItem(int x, int y, int id, boolean bg) {
208 mPlayer.startHitting();
210 if (id > 0) {
211 final Item item = getItem(id);
212 @CheckForNull final String actionKey = item.getActionKey();
213 if (item.isBlock()) {
214 if (!bg) {
215 PlaceBlockActionUtilsKt.placeToForegroundAction(mUseItemActionMap, item, x, y);
216 } else {
217 PlaceBlockActionUtilsKt.placeToBackgroundAction(mUseItemActionMap, item, x, y);
219 } else if (actionKey != null) {
220 final IUseItemAction useItemAction = mUseItemActionMap.get(actionKey);
222 if (useItemAction != null) {
223 useItemAction.perform(item, x, y);
224 } else {
225 Gdx.app.error(TAG, "use item action " + actionKey + "not found");
231 private void hitMobs() {
232 final Player player = mMobsController.getPlayer();
233 mMobsController.getMobs().forEach((mob) -> {
234 if (Intersector.overlaps(mob, player)) {
235 mob.damage(5);
236 mob.jump();
238 });
241 private void pressLMB() {
242 if (mMainConfig.checkGameUiWindow(GameUiWindow.NONE)) {
243 mPlayer.startHitting();
245 if ((mGameWorld.hasForeAt(mCurX, mCurY) && mGameWorld.getForeMapBlock(mCurX, mCurY).getHp() >= 0) ||
246 (!mGameWorld.hasForeAt(mCurX, mCurY) && mGameWorld.hasBackAt(mCurX, mCurY) &&
247 mGameWorld.getBackMapBlock(mCurX, mCurY).getHp() >= 0)) {
248 if (mPlayer.gameMode == 0) {
249 mBlockDamage++;
250 if (mGameWorld.hasForeAt(mCurX, mCurY)) {
251 if (mBlockDamage >= mGameWorld.getForeMapBlock(mCurX, mCurY).getHp()) {
252 mGameWorld.destroyForeMap(mCurX, mCurY);
253 mBlockDamage = 0;
255 } else if (mGameWorld.hasBackAt(mCurX, mCurY)) {
256 if (mBlockDamage >= mGameWorld.getBackMapBlock(mCurX, mCurY).getHp()) {
257 mGameWorld.destroyBackMap(mCurX, mCurY);
258 mBlockDamage = 0;
261 } else {
262 if (mGameWorld.hasForeAt(mCurX, mCurY)) {
263 mGameWorld.placeToForeground(mCurX, mCurY, 0);
264 } else if (mGameWorld.hasBackAt(mCurX, mCurY)) {
265 mGameWorld.placeToBackground(mCurX, mCurY, 0);
267 mTouchedDown = false;
269 } else {
270 hitMobs();
271 mTouchedDown = false;
276 private boolean insideHotbar(float x, float y) {
277 TextureRegion hotbar = Assets.textureRegions.get("hotbar");
278 return y < hotbar.getRegionHeight() &&
279 Range.open(mMainConfig.getWidth() / 2 - (float) hotbar.getRegionWidth() / 2,
280 mMainConfig.getWidth() / 2 + (float) hotbar.getRegionWidth() / 2).contains(x);
283 private void holdMB() {
284 if (mTouchDownBtn == Input.Buttons.RIGHT) {
285 useItem(mCurX, mCurY, mPlayer.inventory[mPlayer.slot], true);
286 mTouchedDown = false;
287 } else {
288 if (insideHotbar(mTouchDownX, mTouchDownY)) {
289 mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
290 mTouchedDown = false;
295 public void keyDown(int keycode) {
296 mKeyDown = true;
297 mKeyDownCode = keycode;
298 switch (keycode) {
299 case Input.Keys.A:
300 case Input.Keys.D:
301 case Input.Keys.W:
302 case Input.Keys.S:
303 case Input.Keys.SPACE:
304 case Input.Keys.CONTROL_LEFT:
305 wasdPressed(keycode);
306 break;
308 case Input.Keys.ALT_LEFT:
309 if (mMainConfig.isTouch()) {
310 mControlMode = mControlMode == ControlMode.WALK ? ControlMode.CURSOR : ControlMode.WALK;
312 break;
314 case Input.Keys.E:
315 if (mMainConfig.checkGameUiWindow(GameUiWindow.NONE)) {
316 switch (mPlayer.gameMode) {
317 case 0:
318 //TODO survival inv
319 break;
320 case 1:
321 mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
322 break;
324 } else {
325 mMainConfig.setGameUiWindow(GameUiWindow.NONE);
327 break;
329 case Input.Keys.G:
330 mMobsController.addMob(new Pig(mCurX * 16, mCurY * 16));
331 break;
333 case Input.Keys.Q:
334 mGameWorld.placeToForeground(mCurX, mCurY, 8);
335 break;
337 case Input.Keys.GRAVE:
338 mMobsController.getPlayer().gameMode = (mMobsController.getPlayer().gameMode + 1) % 2;
339 break;
341 case Input.Keys.ESCAPE:
342 case Input.Keys.BACK:
343 GameSaver.save(mMainConfig, mDropController, mMobsController, mGameWorld);
344 mMainConfig.getCaveGame().quitGame();
345 break;
347 case Input.Keys.F1:
348 mMainConfig.setShowInfo(!mMainConfig.isShowInfo());
349 break;
351 case Input.Keys.M:
352 mMainConfig.setShowMap(!mMainConfig.isShowMap());
353 break;
357 public void keyUp(int keycode) {
358 switch (keycode) {
359 case Input.Keys.A:
360 case Input.Keys.D:
361 mPlayer.getVelocity().x = 0;
362 if (mMainConfig.isTouch() && mPlayer.swim) {
363 mPlayer.swim = false;
365 break;
367 case Input.Keys.W:
368 case Input.Keys.S:
369 case Input.Keys.SPACE:
370 case Input.Keys.CONTROL_LEFT:
371 if (mPlayer.isFlyMode()) {
372 mPlayer.getVelocity().y = 0;
374 if (mPlayer.swim) {
375 mPlayer.swim = false;
377 break;
381 public void touchDown(float touchX, float touchY, int button) {
382 mTouchDownTime = TimeUtils.millis();
383 mTouchedDown = true;
384 mTouchDownBtn = button;
385 mTouchDownX = touchX;
386 mTouchDownY = touchY;
389 public void touchUp(float screenX, float screenY, int button) {
390 if (mDragging) {
391 mDragging = false;
392 return;
395 if (mMainConfig.isTouch() && mKeyDown) {
396 keyUp(mKeyDownCode);
397 mKeyDown = false;
399 TextureRegion hotbar = Assets.textureRegions.get("hotbar");
400 TextureRegion creative = Assets.textureRegions.get("creative");
401 if (mTouchedDown) {
402 if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY) && insideCreativeInv(screenX, screenY)) {
403 int ix = (int) (screenX - (mMainConfig.getWidth() / 2 - creative.getRegionWidth() / 2 + 8)) / 18;
404 int iy = (int) (screenY - (mMainConfig.getHeight() / 2 - creative.getRegionHeight() / 2 + 18)) / 18;
405 int item = mCreativeScroll * 8 + (ix + iy * 8);
406 if (ix >= 8 || ix < 0 || iy < 0 || iy >= 5) {
407 item = -1;
409 if (item >= 0 && item < GameItems.getItemsSize()) {
410 System.arraycopy(mPlayer.inventory, 0, mPlayer.inventory, 1, 8);
411 mPlayer.inventory[0] = item;
413 } else if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY)) {
414 mMainConfig.setGameUiWindow(GameUiWindow.NONE);
415 } else if (screenY < hotbar.getRegionHeight() &&
416 screenX > mMainConfig.getWidth() / 2 - (float) hotbar.getRegionWidth() / 2 &&
417 screenX < mMainConfig.getWidth() / 2 + (float) hotbar.getRegionWidth() / 2) {
418 mPlayer.slot = (int) ((screenX - (mMainConfig.getWidth() / 2 - hotbar.getRegionWidth() / 2)) / 20);
419 } else if (button == Input.Buttons.RIGHT) {
420 useItem(mCurX, mCurY,
421 mPlayer.inventory[mPlayer.slot], false);
422 } else if (button == Input.Buttons.LEFT) {
423 mBlockDamage = 0;
426 mTouchedDown = false;
429 public void touchDragged(float screenX, float screenY) {
430 if (Math.abs(screenX - mTouchDownX) < 16 && Math.abs(screenY - mTouchDownY) < 16) {
431 return;
434 mDragging = true;
435 if (mMainConfig.checkGameUiWindow(GameUiWindow.CREATIVE_INVENTORY) && Math.abs(screenY - mTouchDownY) > 16) {
436 if (insideCreativeInv(screenX, screenY)) {
437 mCreativeScroll -= (screenY - mTouchDownY) / 16;
438 mTouchDownX = screenX;
439 mTouchDownY = screenY;
440 if (mCreativeScroll < 0) {
441 mCreativeScroll = 0;
443 if (mCreativeScroll > GameProc.MAX_CREATIVE_SCROLL) {
444 mCreativeScroll = GameProc.MAX_CREATIVE_SCROLL;
450 public void scrolled(float amountX, float amountY) {
451 switch (mMainConfig.getGameUiWindow()) {
452 case NONE:
453 mPlayer.slot += (int) amountY;
454 if (mPlayer.slot < 0) {
455 mPlayer.slot = 8;
457 if (mPlayer.slot > 8) {
458 mPlayer.slot = 0;
460 break;
461 case CREATIVE_INVENTORY:
462 mCreativeScroll += (int) amountY;
463 if (mCreativeScroll < 0) {
464 mCreativeScroll = 0;
466 if (mCreativeScroll > GameProc.MAX_CREATIVE_SCROLL) {
467 mCreativeScroll = GameProc.MAX_CREATIVE_SCROLL;
469 break;
473 public int getKeyDownCode() {
474 return mKeyDownCode;
477 public boolean isKeyDown() {
478 return mKeyDown;
481 int getBlockDamage() {
482 return mBlockDamage;
485 int getCurX() {
486 return mCurX;
489 int getCurY() {
490 return mCurY;
493 int getCreativeScroll() {
494 return mCreativeScroll;
497 public ControlMode getControlMode() {
498 return mControlMode;
501 public void setControlMode(ControlMode controlMode) {
502 mControlMode = controlMode;
505 void update() {
506 if (!mTouchedDown) {
507 mPlayer.stopHitting();
508 return;
511 if (mTouchDownBtn == Input.Buttons.LEFT) {
512 pressLMB();
515 if (mTouchedDown && TimeUtils.timeSinceMillis(mTouchDownTime) > 500) {
516 holdMB();