DEADSOFTWARE

Remove java serialization
[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 org.jetbrains.annotations.NotNull;
8 import ru.deadsoftware.cavedroid.game.GameItemsHolder;
9 import ru.deadsoftware.cavedroid.game.mobs.Mob;
10 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
11 import ru.deadsoftware.cavedroid.game.model.block.Block;
12 import ru.deadsoftware.cavedroid.game.model.dto.SaveDataDto;
13 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
14 import ru.deadsoftware.cavedroid.game.model.item.Item;
15 import ru.deadsoftware.cavedroid.game.objects.drop.Drop;
16 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
17 import ru.deadsoftware.cavedroid.game.ui.TooltipManager;
18 import ru.deadsoftware.cavedroid.game.world.GameWorld;
19 import ru.deadsoftware.cavedroid.misc.Assets;
20 import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin;
21 import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt;
23 import javax.annotation.CheckForNull;
25 public class Player extends Mob {
27 private static final int SAVE_DATA_VERSION = 1;
29 private static final float SPEED = 69.072f;
30 private static final float JUMP_VELOCITY = -133.332f;
31 private static final int SURVIVAL_CURSOR_RANGE = 4;
33 public static final int MAX_HEALTH = 20;
34 public static final int INVENTORY_SIZE = 36;
35 public static final int HOTBAR_SIZE = 9;
37 private boolean hitting = false, hittingWithDamage = false;
38 private float hitAnim = 0f;
39 private float hitAnimDelta = ANIMATION_SPEED;
41 public Inventory inventory;
43 public int gameMode;
44 public boolean swim;
45 public float headRotation = 0f;
47 public float blockDamage = 0f;
48 public int cursorX = 0;
49 public int cursorY = 0;
51 @CheckForNull
52 private Vector2 spawnPoint = null;
54 public ControlMode controlMode = ControlMode.WALK;
56 public enum ControlMode {
57 WALK,
58 CURSOR
59 }
61 public Player(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) {
62 super(0, 0, 4, 30, randomDir(), Type.MOB, MAX_HEALTH);
63 inventory = new Inventory(INVENTORY_SIZE, HOTBAR_SIZE, gameItemsHolder, tooltipManager);
64 swim = false;
65 }
67 public void initInventory(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) {
68 inventory.initItems(gameItemsHolder, tooltipManager);
69 }
71 public void respawn(GameWorld gameWorld, GameItemsHolder itemsHolder) {
72 Vector2 pos = getSpawnPoint(gameWorld, itemsHolder);
73 this.x = pos.x;
74 this.y = pos.y;
75 mVelocity.setZero();
76 mDead = false;
77 heal(MAX_HEALTH);
78 }
80 public void decreaseCurrentItemCount(GameItemsHolder gameItemsHolder) {
81 if (gameMode == 1) {
82 return;
83 }
85 final InventoryItem item = inventory.getActiveItem();
86 item.subtract();
87 if (item.getAmount() <= 0) {
88 setCurrentInventorySlotItem(gameItemsHolder.getFallbackItem());
89 }
90 }
92 public void dropCurrentItem(DropController dropController) {
93 final InventoryItem activeItem = inventory.getActiveItem();
95 }
97 private Vector2 getSpawnPoint(GameWorld gameWorld, GameItemsHolder itemsHolder) {
98 if (spawnPoint != null) {
99 return spawnPoint;
102 int y, x = gameWorld.getWidth() / 2;
103 for (y = 0; y <= gameWorld.getWorldConfig().getSeaLevel(); y++) {
104 if (y == gameWorld.getWorldConfig().getSeaLevel()) {
105 for (x = 0; x < gameWorld.getWidth(); x++) {
106 if (gameWorld.getForeMap(x, y).getParams().getHasCollision()) {
107 break;
109 if (x == gameWorld.getWidth() - 1) {
110 gameWorld.setForeMap(x, y, itemsHolder.getBlock("grass"));
111 break;
114 break;
116 if (gameWorld.hasForeAt(x, y) && gameWorld.getForeMap(x, y).hasCollision()) {
117 break;
120 spawnPoint = new Vector2(x * 16 + 8 - getWidth() / 2, (float) y * 16 - getHeight());
121 return spawnPoint;
124 public void setDir(Direction dir) {
125 if (dir != getDirection()) {
126 switchDir();
130 public void setCurrentInventorySlotItem(Item item) {
131 inventory.getItems().set(inventory.getActiveSlot(), item.toInventoryItem());
134 @Override
135 public float getSpeed() {
136 return SPEED;
139 @Override
140 public void jump() {
141 if (!canJump()) {
142 if (gameMode == 1) {
143 if (isFlyMode()) {
144 setFlyMode(false);
145 } else {
146 getVelocity().y = 0f;
147 setFlyMode(true);
150 return;
152 mVelocity.y = JUMP_VELOCITY;
155 private boolean checkBlockCanBeHit(Block block) {
156 return !block.isNone() && block.getParams().getHitPoints() >= 0;
159 /**
160 * @return true if any mob fas hit
161 */
162 private boolean hitMobs(GameItemsHolder gameItemsHolder, MobsController mobsController) {
163 if (!hitting || !hittingWithDamage) {
164 return false;
167 boolean result = false;
168 for (Mob mob : mobsController.getMobs()) {
169 if (overlaps(mob.getHitBox())) {
170 final Item activeItem = inventory.getActiveItem().getItem();
171 final Item.Tool tool = activeItem.isTool() ? (Item.Tool) activeItem : null;
172 if (tool != null) {
173 decreaseCurrentItemCount(gameItemsHolder);
175 result = true;
176 mob.damage(MathUtils.floor(tool != null ? tool.getMobDamageMultiplier() : 1));
179 return result;
182 private void hitBlock(GameWorld gameWorld, GameItemsHolder gameItemsHolder) {
183 if (!hitting || !hittingWithDamage) {
184 return;
187 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
188 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
191 if ((checkBlockCanBeHit(foregroundBlock)) ||
192 (foregroundBlock.isNone() && checkBlockCanBeHit(backgroundBlock))) {
193 if (gameMode == 0) {
194 if (!foregroundBlock.isNone()) {
195 if (blockDamage >= foregroundBlock.getParams().getHitPoints()) {
196 gameWorld.destroyForeMap(cursorX, cursorY);
197 blockDamage = 0;
199 } else if (!backgroundBlock.isNone()) {
200 if (blockDamage >= backgroundBlock.getParams().getHitPoints()) {
201 gameWorld.destroyBackMap(cursorX, cursorY);
202 blockDamage = 0;
205 } else {
206 if (!foregroundBlock.isNone()) {
207 gameWorld.placeToForeground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
208 } else if (!backgroundBlock.isNone()) {
209 gameWorld.placeToBackground(cursorX, cursorY, gameItemsHolder.getFallbackBlock());
211 stopHitting();
213 } else {
214 stopHitting();
218 @Override
219 public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) {
220 updateAnimation(delta);
222 if (!hitMobs(gameItemsHolder, mobsController)) {
223 hitBlock(gameWorld, gameItemsHolder);
224 } else {
225 stopHitting();
228 if (gameMode == 1) {
229 return;
232 final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY);
233 final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY);
234 @CheckForNull final Block target;
236 if (checkBlockCanBeHit(foregroundBlock)) {
237 target = foregroundBlock;
238 } else if (checkBlockCanBeHit(backgroundBlock)) {
239 target = backgroundBlock;
240 } else {
241 target = null;
244 final boolean canHitBlock = target != null;
246 float multiplier = 1f;
247 final Item currentItem = inventory.getActiveItem().getItem();
248 if (currentItem instanceof Item.Tool && canHitBlock) {
249 if (target.getParams().getToolType() == currentItem.getClass()
250 && ((Item.Tool)currentItem).getLevel() >= target.getParams().getToolLevel()) {
251 multiplier = 2f * ((Item.Tool)currentItem).getLevel();
253 multiplier *= ((Item.Tool)currentItem).getBlockDamageMultiplier();
256 if (hitting && hittingWithDamage && canHitBlock) {
257 blockDamage += 60f * delta * multiplier;
258 } else {
259 blockDamage = 0f;
263 @Override
264 public void changeDir() {
267 @Override
268 public void damage(int damage) {
269 if (gameMode == 1) {
270 return;
273 if (damage > 0) {
274 getVelocity().y += JUMP_VELOCITY / 3f;
277 super.damage(damage);
280 @Override
281 public void heal(int heal) {
282 if (gameMode == 1) {
283 return;
285 super.heal(heal);
288 public void checkCursorBounds(GameWorld gameWorld) {
289 if (gameMode == 0) {
290 int minCursorX = getMapX() - SURVIVAL_CURSOR_RANGE;
291 int maxCursorX = getMapX() + SURVIVAL_CURSOR_RANGE;
292 int minCursorY = getMiddleMapY() - SURVIVAL_CURSOR_RANGE;
293 int maxCursorY = getMiddleMapY() + SURVIVAL_CURSOR_RANGE;
295 cursorX = MathUtils.clamp(cursorX, minCursorX, maxCursorX);
296 cursorY = MathUtils.clamp(cursorY, minCursorY, maxCursorY);
299 cursorY = MathUtils.clamp(cursorY, 0, gameWorld.getHeight() - 1);
302 private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) {
303 final Item item = inventory.getActiveItem().getItem();
305 if (item == null || item.isNone()) {
306 return;
309 final Sprite sprite = item.getSprite();
310 final boolean smallSprite = !item.isTool() || item.isShears();
312 final float originalWidth = sprite.getWidth();
313 final float originalHeight = sprite.getHeight();
315 if (smallSprite) {
316 sprite.setSize(Drop.DROP_SIZE, Drop.DROP_SIZE);
319 final float handLength = Assets.playerSprite[0][2].getHeight();
321 final SpriteOrigin spriteOrigin = item.getParams().getInHandSpriteOrigin();
322 final int handMultiplier = -getDirection().getBasis();
323 final float xOffset = (-1 + getDirection().getIndex()) * sprite.getWidth() + 4 + handMultiplier * (sprite.getWidth() * spriteOrigin.getX());
324 final float yOffset = !smallSprite ? -sprite.getHeight() / 2 : 0;
326 float rotate = anim + 30;
328 if (item.isTool()) {
329 sprite.rotate90(looksLeft());
332 final float itemX = x + handLength * MathUtils.sin(handMultiplier * anim * MathUtils.degRad) + xOffset;
333 final float itemY = y + handLength * MathUtils.cos(handMultiplier * anim * MathUtils.degRad) + yOffset;
335 if (looksLeft()) {
336 sprite.setFlip(!item.isTool(), sprite.isFlipY());
337 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin.getFlipped(true, false));
338 } else {
339 sprite.setFlip(item.isTool(), sprite.isFlipY());
340 SpriteUtilsKt.applyOrigin(sprite, spriteOrigin);
343 sprite.setRotation(-handMultiplier * rotate);
344 sprite.setPosition(itemX, itemY);
345 sprite.draw(spriteBatch);
347 // dont forget to reset
348 sprite.setFlip(false, sprite.isFlipY());
349 sprite.setRotation(0);
350 sprite.setOriginCenter();
351 sprite.setSize(originalWidth, originalHeight);
352 if (item.isTool()) {
353 sprite.rotate90(looksRight());
357 public void startHitting(boolean withDamage) {
358 if (hitting) {
359 return;
362 hitting = true;
363 hittingWithDamage = withDamage;
364 hitAnim = 90f;
365 hitAnimDelta = ANIMATION_SPEED;
368 public void startHitting() {
369 startHitting(true);
372 public void stopHitting() {
373 blockDamage = 0f;
374 hitting = false;
377 private float getRightHandAnim(float delta) {
378 hitAnim -= hitAnimDelta * delta;
380 if (hitAnim < 30f || hitAnim > 90f) {
381 if (hitting) {
382 hitAnim = MathUtils.clamp(hitAnim, 30f, 90f);
383 hitAnimDelta = -hitAnimDelta;
384 } else {
385 hitAnimDelta = ANIMATION_SPEED;
389 if (!hitting) {
390 if (hitAnim < hitAnimDelta * delta) {
391 hitAnim = 0;
392 hitAnimDelta = 0;
393 return -mAnim;
397 return hitAnim;
400 @Override
401 public void draw(SpriteBatch spriteBatch, float x, float y, float delta) {
402 final Sprite backHand = Assets.playerSprite[1][2];
403 final Sprite backLeg = Assets.playerSprite[1][3];
404 final Sprite frontLeg = Assets.playerSprite[0][3];
405 final Sprite head = Assets.playerSprite[getDirection().getIndex()][0];
406 final Sprite body = Assets.playerSprite[getDirection().getIndex()][1];
407 final Sprite frontHand = Assets.playerSprite[0][2];
409 float backHandAnim, frontHandAnim;
411 final float rightHandAnim = getRightHandAnim(delta);
413 if (looksLeft()) {
414 backHandAnim = rightHandAnim;
415 frontHandAnim = mAnim;
416 } else {
417 backHandAnim = -mAnim;
418 frontHandAnim = -rightHandAnim;
421 backHand.setColor(getTintColor());
422 backLeg.setColor(getTintColor());
423 frontLeg.setColor(getTintColor());
424 head.setColor(getTintColor());
425 body.setColor(getTintColor());
426 frontHand.setColor(getTintColor());
428 SpriteUtilsKt.drawSprite(spriteBatch, backHand, x + 2, y + 8, backHandAnim);
430 if (looksLeft()) {
431 drawItem(spriteBatch, x, y, -backHandAnim);
434 SpriteUtilsKt.drawSprite(spriteBatch, backLeg, x + 2, y + 20, mAnim);
435 SpriteUtilsKt.drawSprite(spriteBatch, frontLeg, x + 2, y + 20, -mAnim);
436 SpriteUtilsKt.drawSprite(spriteBatch, head, x, y, headRotation);
437 SpriteUtilsKt.drawSprite(spriteBatch, body, x + 2, y + 8);
439 if (looksRight()) {
440 drawItem(spriteBatch, x, y, frontHandAnim);
443 SpriteUtilsKt.drawSprite(spriteBatch, frontHand, x + 2, y + 8, frontHandAnim);
446 @NotNull
447 @Override
448 public SaveDataDto.PlayerSaveData getSaveData() {
449 return new SaveDataDto.PlayerSaveData(
450 SAVE_DATA_VERSION,
451 mType,
452 mAnimDelta,
453 mAnim,
454 mDirection,
455 mDead,
456 mCanJump,
457 mFlyMode,
458 mMaxHealth,
459 mHealth,
460 x,
461 y,
462 width,
463 height,
464 getVelocity().x,
465 getVelocity().y,
466 hitting,
467 hittingWithDamage,
468 hitAnim,
469 hitAnimDelta,
470 inventory.getSaveData(),
471 gameMode,
472 swim,
473 headRotation,
474 blockDamage,
475 cursorX,
476 cursorY,
477 spawnPoint != null ? spawnPoint.x : 0f,
478 spawnPoint != null ? spawnPoint.y : 0f,
479 controlMode
480 );
483 public static Player fromSaveData(
484 SaveDataDto.PlayerSaveData saveData,
485 GameItemsHolder gameItemsHolder,
486 TooltipManager tooltipManager
487 ) {
488 saveData.verifyVersion(SAVE_DATA_VERSION);
490 Player player = new Player(gameItemsHolder, tooltipManager);
492 player.mType = saveData.getType();
493 player.mAnimDelta = saveData.getAnimDelta();
494 player.mAnim = saveData.getAnim();
495 player.mDirection = saveData.getDirection();
496 player.mDead = saveData.getDead();
497 player.mCanJump = saveData.getCanJump();
498 player.mFlyMode = saveData.getFlyMode();
499 player.mMaxHealth = saveData.getMaxHealth();
500 player.mHealth = saveData.getHealth();
501 player.x = saveData.getX();
502 player.y = saveData.getY();
503 player.width = saveData.getWidth();
504 player.height = saveData.getHeight();
505 player.hitting = saveData.getHitting();
506 player.hittingWithDamage = saveData.getHittingWithDamage();
507 player.hitAnim = saveData.getHitAnim();
508 player.hitAnimDelta = saveData.getHitAnimDelta();
509 player.inventory = Inventory.Companion.fromSaveData(saveData.getInventory(), gameItemsHolder, tooltipManager);
510 player.gameMode = saveData.getGameMode();
511 player.swim = saveData.getSwim();
512 player.headRotation = saveData.getHeadRotation();
513 player.blockDamage = saveData.getBlockDamage();
514 player.cursorX = saveData.getCursorX();
515 player.cursorY = saveData.getCursorY();
516 player.spawnPoint = new Vector2(saveData.getSpawnPointX(), saveData.getSpawnPointY());
517 player.controlMode = saveData.getControlMode();
519 return player;