DEADSOFTWARE

58ddc025c849feaa37d91a71a5607d5e4b1c04ad
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / mobs / player / Player.java
1 package ru.deadsoftware.cavedroid.game.mobs.player;
3 import com.badlogic.gdx.graphics.g2d.Sprite;
4 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
5 import com.badlogic.gdx.math.MathUtils;
6 import com.badlogic.gdx.math.Vector2;
7 import ru.deadsoftware.cavedroid.game.GameItemsHolder;
8 import ru.deadsoftware.cavedroid.game.mobs.Mob;
9 import ru.deadsoftware.cavedroid.game.model.block.Block;
10 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
11 import ru.deadsoftware.cavedroid.game.model.item.Item;
12 import ru.deadsoftware.cavedroid.game.objects.Drop;
13 import ru.deadsoftware.cavedroid.game.ui.TooltipManager;
14 import ru.deadsoftware.cavedroid.game.world.GameWorld;
15 import ru.deadsoftware.cavedroid.misc.Assets;
16 import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin;
17 import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt;
19 import javax.annotation.CheckForNull;
21 public class Player extends Mob {
23 private static final float SPEED = 69.072f;
24 private static final float JUMP_VELOCITY = -133.332f;
25 private static final int SURVIVAL_CURSOR_RANGE = 4;
27 public static final int MAX_HEALTH = 20;
28 public static final int INVENTORY_SIZE = 36;
29 public static final int HOTBAR_SIZE = 9;
31 private boolean hitting = false, hittingWithDamage = false;
32 private float hitAnim = 0f;
33 private float hitAnimDelta = ANIMATION_SPEED;
35 public final Inventory inventory;
37 public int gameMode;
38 public boolean swim;
39 public float headRotation = 0f;
41 public float blockDamage = 0f;
42 public int cursorX = 0;
43 public int cursorY = 0;
45 @CheckForNull
46 private Vector2 spawnPoint = null;
48 public ControlMode controlMode = ControlMode.WALK;
50 public enum ControlMode {
51 WALK,
52 CURSOR
53 }
55 public Player(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) {
56 super(0, 0, 4, 30, randomDir(), Type.MOB, MAX_HEALTH);
57 inventory = new Inventory(INVENTORY_SIZE, HOTBAR_SIZE, gameItemsHolder, tooltipManager);
58 swim = false;
59 }
61 public void initInventory(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) {
62 inventory.initItems(gameItemsHolder, tooltipManager);
63 }
65 public void respawn(GameWorld gameWorld, GameItemsHolder itemsHolder) {
66 Vector2 pos = getSpawnPoint(gameWorld, itemsHolder);
67 this.x = pos.x;
68 this.y = pos.y;
69 mVelocity.setZero();
70 mDead = false;
71 heal(MAX_HEALTH);
72 }
74 public void decreaseCurrentItemCount(GameItemsHolder gameItemsHolder) {
75 if (gameMode == 1) {
76 return;
77 }
79 final InventoryItem item = inventory.getActiveItem();
80 item.subtract();
81 if (item.getAmount() <= 0) {
82 setCurrentInventorySlotItem(gameItemsHolder.getFallbackItem());
83 }
84 }
86 private Vector2 getSpawnPoint(GameWorld gameWorld, GameItemsHolder itemsHolder) {
87 if (spawnPoint != null) {
88 return spawnPoint;
89 }
91 int y, x = gameWorld.getWidth() / 2;
92 for (y = 0; y <= gameWorld.getWorldConfig().getSeaLevel(); y++) {
93 if (y == gameWorld.getWorldConfig().getSeaLevel()) {
94 for (x = 0; x < gameWorld.getWidth(); x++) {
95 if (gameWorld.getForeMap(x, y).getParams().getHasCollision()) {
96 break;
97 }
98 if (x == gameWorld.getWidth() - 1) {
99 gameWorld.setForeMap(x, y, itemsHolder.getBlock("grass"));
100 break;
103 break;
105 if (gameWorld.hasForeAt(x, y) && gameWorld.getForeMap(x, y).hasCollision()) {
106 break;
109 spawnPoint = new Vector2(x * 16 + 8 - getWidth() / 2, (float) y * 16 - getHeight());
110 return spawnPoint;
113 public void setDir(Direction dir) {
114 if (dir != getDirection()) {
115 switchDir();
119 public void setCurrentInventorySlotItem(Item item) {
120 inventory.getItems().set(inventory.getActiveSlot(), item.toInventoryItem());
123 @Override
124 public float getSpeed() {
125 return SPEED;
128 @Override
129 public void jump() {
130 if (!canJump()) {
131 if (gameMode == 1) {
132 if (isFlyMode()) {
133 setFlyMode(false);
134 } else {
135 getVelocity().y = 0f;
136 setFlyMode(true);
139 return;
141 mVelocity.y = JUMP_VELOCITY;
144 private boolean checkBlockCanBeHit(Block block) {
145 return !block.isNone() && block.getParams().getHitPoints() >= 0;
148 private void hitBlock(GameWorld gameWorld, GameItemsHolder gameItemsHolder) {
149 if (!hitting || !hittingWithDamage) {
150 return;
153 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
154 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
157 if ((checkBlockCanBeHit(foregroundBlock)) ||
158 (foregroundBlock.isNone() && checkBlockCanBeHit(backgroundBlock))) {
159 if (gameMode == 0) {
160 if (!foregroundBlock.isNone()) {
161 if (blockDamage >= foregroundBlock.getParams().getHitPoints()) {
162 gameWorld.destroyForeMap(cursorX, cursorY);
163 blockDamage = 0;
165 } else if (!backgroundBlock.isNone()) {
166 if (blockDamage >= backgroundBlock.getParams().getHitPoints()) {
167 gameWorld.destroyBackMap(cursorX, cursorY);
168 blockDamage = 0;
171 } else {
172 if (!foregroundBlock.isNone()) {
173 gameWorld.placeToForeground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
174 } else if (!backgroundBlock.isNone()) {
175 gameWorld.placeToBackground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
177 stopHitting();
179 } else {
180 stopHitting();
184 @Override
185 public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) {
186 updateAnimation(delta);
187 hitBlock(gameWorld, gameItemsHolder);
189 if (gameMode == 1) {
190 return;
193 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
194 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
195 @CheckForNull final Block target;
197 if (checkBlockCanBeHit(foregroundBlock)) {
198 target = foregroundBlock;
199 } else if (checkBlockCanBeHit(backgroundBlock)) {
200 target = backgroundBlock;
201 } else {
202 target = null;
205 final boolean canHitBlock = target != null;
207 float multiplier = 1f;
208 final Item currentItem = inventory.getActiveItem().getItem();
209 if (currentItem instanceof Item.Tool && canHitBlock) {
210 if (target.getParams().getToolType() == currentItem.getClass()
211 && ((Item.Tool)currentItem).getLevel() >= target.getParams().getToolLevel()) {
212 multiplier = 2f * ((Item.Tool)currentItem).getLevel();
214 multiplier *= ((Item.Tool)currentItem).getBlockDamageMultiplier();
217 if (hitting && hittingWithDamage && canHitBlock) {
218 blockDamage += 60f * delta * multiplier;
219 } else {
220 blockDamage = 0f;
224 @Override
225 public void changeDir() {
228 @Override
229 public void damage(int damage) {
230 if (gameMode == 1) {
231 return;
234 if (damage > 0) {
235 getVelocity().y += JUMP_VELOCITY / 3f;
238 super.damage(damage);
241 @Override
242 public void heal(int heal) {
243 if (gameMode == 1) {
244 return;
246 super.heal(heal);
249 public void checkCursorBounds(GameWorld gameWorld) {
250 if (gameMode == 0) {
251 int minCursorX = getMapX() - SURVIVAL_CURSOR_RANGE;
252 int maxCursorX = getMapX() + SURVIVAL_CURSOR_RANGE;
253 int minCursorY = getMiddleMapY() - SURVIVAL_CURSOR_RANGE;
254 int maxCursorY = getMiddleMapY() + SURVIVAL_CURSOR_RANGE;
256 cursorX = MathUtils.clamp(cursorX, minCursorX, maxCursorX);
257 cursorY = MathUtils.clamp(cursorY, minCursorY, maxCursorY);
260 cursorY = MathUtils.clamp(cursorY, 0, gameWorld.getHeight() - 1);
263 private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) {
264 final Item item = inventory.getActiveItem().getItem();
266 if (item == null || item.isNone()) {
267 return;
270 final Sprite sprite = item.getSprite();
271 final boolean smallSprite = !item.isTool() || item.isShears();
273 final float originalWidth = sprite.getWidth();
274 final float originalHeight = sprite.getHeight();
276 if (smallSprite) {
277 sprite.setSize(Drop.DROP_SIZE, Drop.DROP_SIZE);
280 final float handLength = Assets.playerSprite[0][2].getHeight();
282 final SpriteOrigin spriteOrigin = item.getParams().getInHandSpriteOrigin();
283 final int handMultiplier = -getDirection().getBasis();
284 final float xOffset = (-1 + getDirection().getIndex()) * sprite.getWidth() + 4 + handMultiplier * (sprite.getWidth() * spriteOrigin.getX());
285 final float yOffset = !smallSprite ? -sprite.getHeight() / 2 : 0;
287 float rotate = anim + 30;
289 if (item.isTool()) {
290 sprite.rotate90(looksLeft());
293 final float itemX = x + handLength * MathUtils.sin(handMultiplier * anim * MathUtils.degRad) + xOffset;
294 final float itemY = y + handLength * MathUtils.cos(handMultiplier * anim * MathUtils.degRad) + yOffset;
296 if (looksLeft()) {
297 sprite.setFlip(!item.isTool(), sprite.isFlipY());
298 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin.getFlipped(true, false));
299 } else {
300 sprite.setFlip(item.isTool(), sprite.isFlipY());
301 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin);
304 sprite.setRotation(-handMultiplier * rotate);
305 sprite.setPosition(itemX, itemY);
306 sprite.draw(spriteBatch);
308 // dont forget to reset
309 sprite.setFlip(false, sprite.isFlipY());
310 sprite.setRotation(0);
311 sprite.setOriginCenter();
312 sprite.setSize(originalWidth, originalHeight);
313 if (item.isTool()) {
314 sprite.rotate90(looksRight());
318 public void startHitting(boolean withDamage) {
319 if (hitting) {
320 return;
323 hitting = true;
324 hittingWithDamage = withDamage;
325 hitAnim = 90f;
326 hitAnimDelta = ANIMATION_SPEED;
329 public void startHitting() {
330 startHitting(true);
333 public void stopHitting() {
334 blockDamage = 0f;
335 hitting = false;
338 private float getRightHandAnim(float delta) {
339 hitAnim -= hitAnimDelta * delta;
341 if (hitAnim < 30f || hitAnim > 90f) {
342 if (hitting) {
343 hitAnim = MathUtils.clamp(hitAnim, 30f, 90f);
344 hitAnimDelta = -hitAnimDelta;
345 } else {
346 hitAnimDelta = ANIMATION_SPEED;
350 if (!hitting) {
351 if (hitAnim < hitAnimDelta * delta) {
352 hitAnim = 0;
353 hitAnimDelta = 0;
354 return -mAnim;
358 return hitAnim;
361 @Override
362 public void draw(SpriteBatch spriteBatch, float x, float y, float delta) {
363 final Sprite backHand = Assets.playerSprite[1][2];
364 final Sprite backLeg = Assets.playerSprite[1][3];
365 final Sprite frontLeg = Assets.playerSprite[0][3];
366 final Sprite head = Assets.playerSprite[getDirection().getIndex()][0];
367 final Sprite body = Assets.playerSprite[getDirection().getIndex()][1];
368 final Sprite frontHand = Assets.playerSprite[0][2];
370 float backHandAnim, frontHandAnim;
372 final float rightHandAnim = getRightHandAnim(delta);
374 if (looksLeft()) {
375 backHandAnim = rightHandAnim;
376 frontHandAnim = mAnim;
377 } else {
378 backHandAnim = -mAnim;
379 frontHandAnim = -rightHandAnim;
382 SpriteUtilsKt.drawSprite(spriteBatch, backHand, x + 2, y + 8, backHandAnim);
384 if (looksLeft()) {
385 drawItem(spriteBatch, x, y, -backHandAnim);
388 SpriteUtilsKt.drawSprite(spriteBatch, backLeg, x + 2, y + 20, mAnim);
389 SpriteUtilsKt.drawSprite(spriteBatch, frontLeg, x + 2, y + 20, -mAnim);
390 SpriteUtilsKt.drawSprite(spriteBatch, head, x, y, headRotation);
391 SpriteUtilsKt.drawSprite(spriteBatch, body, x + 2, y + 8);
393 if (looksRight()) {
394 drawItem(spriteBatch, x, y, frontHandAnim);
397 SpriteUtilsKt.drawSprite(spriteBatch, frontHand, x + 2, y + 8, frontHandAnim);