DEADSOFTWARE

Drop items on Q and add empty hearts to health bar
[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.world.GameWorld;
14 import ru.deadsoftware.cavedroid.misc.Assets;
15 import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin;
16 import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt;
18 import javax.annotation.CheckForNull;
20 public class Player extends Mob {
22 private static final float SPEED = 69.072f;
23 private static final float JUMP_VELOCITY = -133.332f;
25 public static final int MAX_HEALTH = 20;
26 public static final int INVENTORY_SIZE = 36;
27 public static final int HOTBAR_SIZE = 9;
29 private boolean hitting = false, hittingWithDamage = false;
30 private float hitAnim = 0f;
31 private float hitAnimDelta = ANIMATION_SPEED;
33 public final Inventory inventory;
35 public int gameMode;
36 public boolean swim;
37 public float headRotation = 0f;
39 public float blockDamage = 0f;
40 public int cursorX = 0;
41 public int cursorY = 0;
43 @CheckForNull
44 private Vector2 spawnPoint = null;
46 public ControlMode controlMode = ControlMode.WALK;
48 public enum ControlMode {
49 WALK,
50 CURSOR
51 }
53 public Player(GameItemsHolder gameItemsHolder) {
54 super(0, 0, 4, 30, randomDir(), Type.MOB, MAX_HEALTH);
55 inventory = new Inventory(INVENTORY_SIZE, HOTBAR_SIZE, gameItemsHolder);
56 swim = false;
57 }
59 public void initInventory(GameItemsHolder gameItemsHolder) {
60 inventory.initItems(gameItemsHolder);
61 }
63 public void respawn(GameWorld gameWorld, GameItemsHolder itemsHolder) {
64 Vector2 pos = getSpawnPoint(gameWorld, itemsHolder);
65 this.x = pos.x;
66 this.y = pos.y;
67 mVelocity.setZero();
68 mDead = false;
69 heal(MAX_HEALTH);
70 }
72 public void decreaseCurrentItemCount(GameItemsHolder gameItemsHolder) {
73 if (gameMode == 1) {
74 return;
75 }
77 final InventoryItem item = inventory.getActiveItem();
78 item.subtract();
79 if (item.getAmount() <= 0) {
80 setCurrentInventorySlotItem(gameItemsHolder.getFallbackItem());
81 }
82 }
84 private Vector2 getSpawnPoint(GameWorld gameWorld, GameItemsHolder itemsHolder) {
85 if (spawnPoint != null) {
86 return spawnPoint;
87 }
89 int y, x = gameWorld.getWidth() / 2;
90 for (y = 0; y <= gameWorld.getWorldConfig().getSeaLevel(); y++) {
91 if (y == gameWorld.getWorldConfig().getSeaLevel()) {
92 for (x = 0; x < gameWorld.getWidth(); x++) {
93 if (gameWorld.getForeMap(x, y).getParams().getHasCollision()) {
94 break;
95 }
96 if (x == gameWorld.getWidth() - 1) {
97 gameWorld.setForeMap(x, y, itemsHolder.getBlock("grass"));
98 break;
99 }
101 break;
103 if (gameWorld.hasForeAt(x, y) && gameWorld.getForeMap(x, y).hasCollision()) {
104 break;
107 spawnPoint = new Vector2(x * 16 + 8 - getWidth() / 2, (float) y * 16 - getHeight());
108 return spawnPoint;
111 public void setDir(Direction dir) {
112 if (dir != getDirection()) {
113 switchDir();
117 public void setCurrentInventorySlotItem(Item item) {
118 inventory.getItems().set(inventory.getActiveSlot(), item.toInventoryItem());
121 @Override
122 public float getSpeed() {
123 return SPEED;
126 @Override
127 public void jump() {
128 mVelocity.y = JUMP_VELOCITY;
131 private boolean checkBlockCanBeHit(Block block) {
132 return !block.isNone() && block.getParams().getHitPoints() >= 0;
135 private void hitBlock(GameWorld gameWorld, GameItemsHolder gameItemsHolder) {
136 if (!hitting || !hittingWithDamage) {
137 return;
140 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
141 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
144 if ((checkBlockCanBeHit(foregroundBlock)) ||
145 (foregroundBlock.isNone() && checkBlockCanBeHit(backgroundBlock))) {
146 if (gameMode == 0) {
147 if (!foregroundBlock.isNone()) {
148 if (blockDamage >= foregroundBlock.getParams().getHitPoints()) {
149 gameWorld.destroyForeMap(cursorX, cursorY);
150 blockDamage = 0;
152 } else if (!backgroundBlock.isNone()) {
153 if (blockDamage >= backgroundBlock.getParams().getHitPoints()) {
154 gameWorld.destroyBackMap(cursorX, cursorY);
155 blockDamage = 0;
158 } else {
159 if (!foregroundBlock.isNone()) {
160 gameWorld.placeToForeground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
161 } else if (!backgroundBlock.isNone()) {
162 gameWorld.placeToBackground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
164 stopHitting();
166 } else {
167 stopHitting();
171 @Override
172 public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) {
173 updateAnimation(delta);
174 hitBlock(gameWorld, gameItemsHolder);
176 if (gameMode == 1) {
177 return;
180 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
181 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
182 @CheckForNull final Block target;
184 if (checkBlockCanBeHit(foregroundBlock)) {
185 target = foregroundBlock;
186 } else if (checkBlockCanBeHit(backgroundBlock)) {
187 target = backgroundBlock;
188 } else {
189 target = null;
192 final boolean canHitBlock = target != null;
194 float multiplier = 1f;
195 final Item currentItem = inventory.getActiveItem().getItem();
196 if (currentItem instanceof Item.Tool && canHitBlock) {
197 if (target.getParams().getToolType() == currentItem.getClass()
198 && ((Item.Tool)currentItem).getLevel() >= target.getParams().getToolLevel()) {
199 multiplier = 2f * ((Item.Tool)currentItem).getLevel();
201 multiplier *= ((Item.Tool)currentItem).getBlockDamageMultiplier();
204 if (hitting && hittingWithDamage && canHitBlock) {
205 blockDamage += 60f * delta * multiplier;
206 } else {
207 blockDamage = 0f;
211 @Override
212 public void changeDir() {
215 @Override
216 public void damage(int damage) {
217 if (gameMode == 1) {
218 return;
221 if (damage > 0) {
222 getVelocity().y += JUMP_VELOCITY / 3f;
225 super.damage(damage);
228 @Override
229 public void heal(int heal) {
230 if (gameMode == 1) {
231 return;
233 super.heal(heal);
236 private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) {
237 final Item item = inventory.getActiveItem().getItem();
239 if (item == null || item.isNone()) {
240 return;
243 final Sprite sprite = item.getSprite();
244 final boolean smallSprite = !item.isTool() || item.isShears();
246 final float originalWidth = sprite.getWidth();
247 final float originalHeight = sprite.getHeight();
249 if (smallSprite) {
250 sprite.setSize(Drop.DROP_SIZE, Drop.DROP_SIZE);
253 final float handLength = Assets.playerSprite[0][2].getHeight();
255 final SpriteOrigin spriteOrigin = item.getParams().getInHandSpriteOrigin();
256 final int handMultiplier = -getDirection().getBasis();
257 final float xOffset = (-1 + getDirection().getIndex()) * sprite.getWidth() + 4 + handMultiplier * (sprite.getWidth() * spriteOrigin.getX());
258 final float yOffset = !smallSprite ? -sprite.getHeight() / 2 : 0;
260 float rotate = anim + 30;
262 if (item.isTool()) {
263 sprite.rotate90(looksLeft());
266 final float itemX = x + handLength * MathUtils.sin(handMultiplier * anim * MathUtils.degRad) + xOffset;
267 final float itemY = y + handLength * MathUtils.cos(handMultiplier * anim * MathUtils.degRad) + yOffset;
269 if (looksLeft()) {
270 sprite.setFlip(!item.isTool(), sprite.isFlipY());
271 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin.getFlipped(true, false));
272 } else {
273 sprite.setFlip(item.isTool(), sprite.isFlipY());
274 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin);
277 sprite.setRotation(-handMultiplier * rotate);
278 sprite.setPosition(itemX, itemY);
279 sprite.draw(spriteBatch);
281 // dont forget to reset
282 sprite.setFlip(false, sprite.isFlipY());
283 sprite.setRotation(0);
284 sprite.setOriginCenter();
285 sprite.setSize(originalWidth, originalHeight);
286 if (item.isTool()) {
287 sprite.rotate90(looksRight());
291 public void startHitting(boolean withDamage) {
292 if (hitting) {
293 return;
296 hitting = true;
297 hittingWithDamage = withDamage;
298 hitAnim = 90f;
299 hitAnimDelta = ANIMATION_SPEED;
302 public void startHitting() {
303 startHitting(true);
306 public void stopHitting() {
307 blockDamage = 0f;
308 hitting = false;
311 private float getRightHandAnim(float delta) {
312 hitAnim -= hitAnimDelta * delta;
314 if (hitAnim < 30f || hitAnim > 90f) {
315 if (hitting) {
316 hitAnim = MathUtils.clamp(hitAnim, 30f, 90f);
317 hitAnimDelta = -hitAnimDelta;
318 } else {
319 hitAnimDelta = ANIMATION_SPEED;
323 if (!hitting) {
324 if (hitAnim < hitAnimDelta * delta) {
325 hitAnim = 0;
326 hitAnimDelta = 0;
327 return -mAnim;
331 return hitAnim;
334 @Override
335 public void draw(SpriteBatch spriteBatch, float x, float y, float delta) {
336 final Sprite backHand = Assets.playerSprite[1][2];
337 final Sprite backLeg = Assets.playerSprite[1][3];
338 final Sprite frontLeg = Assets.playerSprite[0][3];
339 final Sprite head = Assets.playerSprite[getDirection().getIndex()][0];
340 final Sprite body = Assets.playerSprite[getDirection().getIndex()][1];
341 final Sprite frontHand = Assets.playerSprite[0][2];
343 float backHandAnim, frontHandAnim;
345 final float rightHandAnim = getRightHandAnim(delta);
347 if (looksLeft()) {
348 backHandAnim = rightHandAnim;
349 frontHandAnim = mAnim;
350 } else {
351 backHandAnim = -mAnim;
352 frontHandAnim = -rightHandAnim;
355 SpriteUtilsKt.drawSprite(spriteBatch, backHand, x + 2, y + 8, backHandAnim);
357 if (looksLeft()) {
358 drawItem(spriteBatch, x, y, -backHandAnim);
361 SpriteUtilsKt.drawSprite(spriteBatch, backLeg, x + 2, y + 20, mAnim);
362 SpriteUtilsKt.drawSprite(spriteBatch, frontLeg, x + 2, y + 20, -mAnim);
363 SpriteUtilsKt.drawSprite(spriteBatch, head, x, y, headRotation);
364 SpriteUtilsKt.drawSprite(spriteBatch, body, x + 2, y + 8);
366 if (looksRight()) {
367 drawItem(spriteBatch, x, y, frontHandAnim);
370 SpriteUtilsKt.drawSprite(spriteBatch, frontHand, x + 2, y + 8, frontHandAnim);