package de.miaurizius.jgame2d.entity; import de.miaurizius.jgame2d.core.*; import de.miaurizius.jgame2d.core.enums.Direction; import de.miaurizius.jgame2d.core.enums.EntityType; import de.miaurizius.jgame2d.core.enums.GameState; import de.miaurizius.jgame2d.core.handlers.KeyHandler; import de.miaurizius.jgame2d.entity.item.KeyObj; import de.miaurizius.jgame2d.entity.item.LanternObj; import de.miaurizius.jgame2d.entity.item.ShieldWoodObj; import de.miaurizius.jgame2d.entity.item.SwordNormalObj; import de.miaurizius.jgame2d.entity.projectile.FireballObj; import java.awt.*; import java.awt.image.BufferedImage; import java.lang.reflect.InvocationTargetException; public class Player extends Entity { KeyHandler keyH; public final int screenX; public final int screenY; private int standCount; // STATE public boolean attackCancel; public boolean lightUpdated; public Player(GamePanel panel, KeyHandler keyH) { super(panel); this.keyH = keyH; name = "player"; type = EntityType.PLAYER; screenX = panel.screenWidth/2 - panel.tileSize/2; screenY = panel.screenHeight/2 - panel.tileSize/2; solidArea = new Rectangle(); solidArea.x = 12; solidArea.y = 20; solidAreaDefaultX = solidArea.x; solidAreaDefaultY = solidArea.y; solidArea.width = 24; solidArea.height = 24; setDefaultValues(); getPlayerImage(); getPlayerAttackImage(); getGuardImages(); setDialogue(); } // DEFAULT public void update() { if(life > maxLife) life = maxLife; if(knockback) { collisionOn = false; panel.collisionH.checkTile(this); panel.collisionH.checkObject(this, false); panel.collisionH.checkEntity(this, panel.npc[panel.currentMap.getIndex()]); // panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]); panel.collisionH.checkEntity(this, panel.iTile[panel.currentMap.getIndex()]); if(collisionOn) { knockbackCount = 0; knockback = false; speed = defaultSpeed; invincibleCounting(); return; } switch(knockbackDirection) { case UP -> worldY -= speed; case DOWN -> worldY += speed; case LEFT -> worldX -= speed; case RIGHT -> worldX += speed; } knockbackCount++; if(knockbackCount != 10) { invincibleCounting(); return; } knockback = false; knockbackCount = 0; speed = defaultSpeed; invincibleCounting(); return; } else if(attacking) { attacking(); invincibleCounting(); return; } // BLOCKING if(keyH.CTLKeyPressed) { guarding = true; transparent = false; invincibleCounting(); return; } // MOVEMENT if(keyH.upPressed || keyH.downPressed || keyH.leftPressed || keyH.rightPressed || keyH.spacePressed) { if(!keyH.spacePressed) { if(keyH.upPressed) direction = Direction.UP; else if(keyH.downPressed) direction = Direction.DOWN; else if(keyH.leftPressed) direction = Direction.LEFT; else direction = Direction.RIGHT; } // CHECK TILE COLLISION collisionOn = false; panel.collisionH.checkTile(this); // CHECK OBJECT COLLISION int objIndex = panel.collisionH.checkObject(this, true); pickObject(objIndex); // CHECK ENTITY COLLISION int npcIndex = panel.collisionH.checkEntity(this, panel.npc[panel.currentMap.getIndex()]); interactNPC(npcIndex); // CHECK MONSTER COLLISION int monsterIndex = panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]); interactMonster(monsterIndex); // CHECK INTERACTIVE TILE COLLISION int iTileIndex = panel.collisionH.checkEntity(this, panel.iTile[panel.currentMap.getIndex()]); // CHECK EVENT panel.eventH.checkEvent(); if(!collisionOn && !keyH.spacePressed) { switch (direction) { case UP -> worldY -= speed; case DOWN -> worldY += speed; case LEFT -> worldX -= speed; case RIGHT -> worldX += speed; } } if(keyH.spacePressed && !attackCancel) { panel.playSE(7); attacking = true; spriteCount = 0; } attackCancel = false; panel.keyH.spacePressed = false; guarding = false; spriteCount++; if(spriteCount > 12) { if(spriteNum == 1) spriteNum = 2; else if(spriteNum == 2) spriteNum = 1; else spriteNum = 0; spriteCount = 0; } } else { standCount++; if(standCount == 20) { spriteNum = 1; standCount = 0; } guarding = false; } if(panel.keyH.shotKeyPressed && !projectile.alive) { projectile.set(worldX, worldY, direction, true, this); panel.projectileList.add(projectile); panel.playSE(10); } // INVINCIBLE COUNTER if(!invincible) return; invincibleCounting(); if(life <= 0) { panel.gameState = GameState.GAMEOVER; invincibleCount = 0; panel.ui.commandNum = -1; panel.stopMusic(); panel.playSE(12); } } // INTERACTION public void pickObject(int index) { if(index == 999 || panel.obj[panel.currentMap.getIndex()][index] == null) return; // PICKUP ONLY ITEMS if(panel.obj[panel.currentMap.getIndex()][index].type == EntityType.PICKUP) { panel.obj[panel.currentMap.getIndex()][index].use(this); panel.obj[panel.currentMap.getIndex()][index] = null; return; } // OBSTACLES if(panel.obj[panel.currentMap.getIndex()][index].type == EntityType.OBSTACLE) { if(!keyH.spacePressed) return; attackCancel = true; panel.obj[panel.currentMap.getIndex()][index].interact(); return; } // INVENTORY ITEMS else { if(!canObtainItem(panel.obj[panel.currentMap.getIndex()][index])) { panel.ui.addMessage("Your inventory is full!"); return; } panel.playSE(1); panel.ui.addMessage("Picked up " + panel.obj[panel.currentMap.getIndex()][index].name + "!"); } panel.obj[panel.currentMap.getIndex()][index] = null; } public void interactMonster(int index) { if(index == 999) return; if(invincible || panel.monster[panel.currentMap.getIndex()][index].dying || !panel.monster[panel.currentMap.getIndex()][index].alive) return; int damage = panel.monster[panel.currentMap.getIndex()][index].attack - defense; panel.playSE(6); life -= Math.max(damage, 0); if(damage != 0) panel.player.transparent = true; invincible = true; } public void damageMonster(int index, Entity attacker, int attack, int knockbackVal) { if(index == 999) return; if(panel.monster[panel.currentMap.getIndex()][index].invincible) return; int damage = attack - panel.monster[panel.currentMap.getIndex()][index].defense; if(damage > 0) { panel.playSE(5); if(knockbackVal > 0) setKnockback(panel.monster[panel.currentMap.getIndex()][index], attacker, knockbackVal); panel.monster[panel.currentMap.getIndex()][index].life -= damage; panel.monster[panel.currentMap.getIndex()][index].transparent = true; panel.monster[panel.currentMap.getIndex()][index].invincible = true; } panel.monster[panel.currentMap.getIndex()][index].damageReaction(); if(panel.monster[panel.currentMap.getIndex()][index].life <= 0) { panel.monster[panel.currentMap.getIndex()][index].dying = true; panel.ui.addMessage("Gained +" + panel.monster[panel.currentMap.getIndex()][index].exp + " XP!"); exp += panel.monster[panel.currentMap.getIndex()][index].exp; checkLevelUp(); } } public void interactTile(int index) { if(index == 999 || !panel.iTile[panel.currentMap.getIndex()][index].destructible || panel.iTile[panel.currentMap.getIndex()][index].invincible) return; if(!panel.iTile[panel.currentMap.getIndex()][index].meetItemReq(this)) return; panel.iTile[panel.currentMap.getIndex()][index].playSE(); panel.iTile[panel.currentMap.getIndex()][index].life--; panel.iTile[panel.currentMap.getIndex()][index].invincible = true; generateParticle(panel.iTile[panel.currentMap.getIndex()][index], panel.iTile[panel.currentMap.getIndex()][index]); panel.iTile[panel.currentMap.getIndex()][index].checkDrop(); if(panel.iTile[panel.currentMap.getIndex()][index].life == 0) panel.iTile[panel.currentMap.getIndex()][index] = panel.iTile[panel.currentMap.getIndex()][index].getDestroyedForm(); } public void interactNPC(int index) { if(index == 999) return; if(panel.keyH.spacePressed) { attackCancel = true; panel.npc[panel.currentMap.getIndex()][index].speak(); return; } panel.npc[panel.currentMap.getIndex()][index].move(direction); } public void speak() { //This method only exists for character specific things later... super.speak(); } // BACKGROUND JOBS public void checkLevelUp() { if(exp < nextLevelExp) return; level++; nextLevelExp = nextLevelExp*2; maxLife += 2; strength++; dexterity++; attack = getAttack(); defense = getDefense(); panel.playSE(8); setDialogue(); startDialogue(this,0); } public void selectItem() { int itemIndex = panel.ui.getItemIndex(panel.ui.playerSlotCol, panel.ui.playerSlotRow); if(itemIndex >= inventory.size()) return; Entity selectedItem = inventory.get(itemIndex); if(selectedItem.type == EntityType.WEAPON) { currentWeapon = selectedItem; getAttack(); getPlayerAttackImage(); } if(selectedItem.type == EntityType.SHIELD) { currentShield = selectedItem; getDefense(); } if(selectedItem.type == EntityType.LIGHT) { if(currentLight == selectedItem) currentLight = null; else currentLight = selectedItem; lightUpdated = true; } if(selectedItem.consumable) if(selectedItem.use(this)) if(selectedItem.amt > 1) selectedItem.amt--; else inventory.remove(selectedItem); } public void setDefaultPositions() { worldX = panel.tileSize * 23; worldY = panel.tileSize * 21; direction = Direction.DOWN; } public void restoreStatus() { life = maxLife; speed = defaultSpeed; invincible = false; transparent = false; attacking = false; guarding = false; knockback = false; lightUpdated = true; } public void getSleepingImage(BufferedImage image) { down1 = image; down2 = image; up1 = image; up2 = image; left1 = image; left2 = image; right1 = image; right2 = image; } // SETTING THINGS UP public void setDefaultValues() { worldX = panel.tileSize * 23; worldY = panel.tileSize * 21; defaultSpeed = 4; speed = defaultSpeed; direction = Direction.DOWN; // PLAYER STATUS (1 heart = 2 lives) maxLife = 6; life = maxLife; level = 1; strength = 1; dexterity = 1; exp = 0; nextLevelExp = 5; coins = 500; currentWeapon = new SwordNormalObj(panel); currentShield = new ShieldWoodObj(panel); currentLight = null; projectile = new FireballObj(panel); attack = getAttack(); defense = getDefense(); // INVENTORY inventory.clear(); inventory.add(currentWeapon); inventory.add(currentShield); inventory.add(new KeyObj(panel)); } public void setDialogue() { dialogue[0][0] = "You are level " + level + " now!\nYou feel stronger!"; } public int getAttack() { attackArea = currentWeapon.attackArea; return attack = strength * currentWeapon.attackValue; } public int getDefense() { return defense = dexterity * currentShield.defenseValue; } public int getCurrentWeaponSlot() { for(int i = 0; i < inventory.size(); i++) { if(inventory.get(i) == currentWeapon) return i; } return -1; } public int getCurrentShieldSlot() { for(int i = 0; i < inventory.size(); i++) { if(inventory.get(i) == currentShield) return i; } return -1; } public void getPlayerImage() { up1 = initEntitySprites("player/boy_up_1"); up2 = initEntitySprites("player/boy_up_2"); down1 = initEntitySprites("player/boy_down_1"); down2 = initEntitySprites("player/boy_down_2"); left1 = initEntitySprites("player/boy_left_1"); left2 = initEntitySprites("player/boy_left_2"); right1 = initEntitySprites("player/boy_right_1"); right2 = initEntitySprites("player/boy_right_2"); } public void getPlayerAttackImage() { switch(currentWeapon.weaponType) { case SWORD: attackUp1 = initEntitySprites("player/attack/boy_attack_up_1", panel.tileSize, panel.tileSize * 2); attackUp2 = initEntitySprites("player/attack/boy_attack_up_2", panel.tileSize, panel.tileSize * 2); attackDown1 = initEntitySprites("player/attack/boy_attack_down_1", panel.tileSize, panel.tileSize * 2); attackDown2 = initEntitySprites("player/attack/boy_attack_down_2", panel.tileSize, panel.tileSize * 2); attackLeft1 = initEntitySprites("player/attack/boy_attack_left_1", panel.tileSize * 2, panel.tileSize); attackLeft2 = initEntitySprites("player/attack/boy_attack_left_2", panel.tileSize * 2, panel.tileSize); attackRight1 = initEntitySprites("player/attack/boy_attack_right_1", panel.tileSize * 2, panel.tileSize); attackRight2 = initEntitySprites("player/attack/boy_attack_right_2", panel.tileSize * 2, panel.tileSize); break; case AXE: attackUp1 = initEntitySprites("player/attack/boy_axe_up_1", panel.tileSize, panel.tileSize * 2); attackUp2 = initEntitySprites("player/attack/boy_axe_up_2", panel.tileSize, panel.tileSize * 2); attackDown1 = initEntitySprites("player/attack/boy_axe_down_1", panel.tileSize, panel.tileSize * 2); attackDown2 = initEntitySprites("player/attack/boy_axe_down_2", panel.tileSize, panel.tileSize * 2); attackLeft1 = initEntitySprites("player/attack/boy_axe_left_1", panel.tileSize * 2, panel.tileSize); attackLeft2 = initEntitySprites("player/attack/boy_axe_left_2", panel.tileSize * 2, panel.tileSize); attackRight1 = initEntitySprites("player/attack/boy_axe_right_1", panel.tileSize * 2, panel.tileSize); attackRight2 = initEntitySprites("player/attack/boy_axe_right_2", panel.tileSize * 2, panel.tileSize); break; case PICKAXE: attackUp1 = initEntitySprites("player/attack/boy_pick_up_1", panel.tileSize, panel.tileSize * 2); attackUp2 = initEntitySprites("player/attack/boy_pick_up_2", panel.tileSize, panel.tileSize * 2); attackDown1 = initEntitySprites("player/attack/boy_pick_down_1", panel.tileSize, panel.tileSize * 2); attackDown2 = initEntitySprites("player/attack/boy_pick_down_2", panel.tileSize, panel.tileSize * 2); attackLeft1 = initEntitySprites("player/attack/boy_pick_left_1", panel.tileSize * 2, panel.tileSize); attackLeft2 = initEntitySprites("player/attack/boy_pick_left_2", panel.tileSize * 2, panel.tileSize); attackRight1 = initEntitySprites("player/attack/boy_pick_right_1", panel.tileSize * 2, panel.tileSize); attackRight2 = initEntitySprites("player/attack/boy_pick_right_2", panel.tileSize * 2, panel.tileSize); break; } } public void getGuardImages() { guardUp = initEntitySprites("player/guarding/boy_guard_up"); guardDown = initEntitySprites("player/guarding/boy_guard_down"); guardLeft = initEntitySprites("player/guarding/boy_guard_left"); guardRight = initEntitySprites("player/guarding/boy_guard_right"); } public int searchItemInInventory(String itemName) { for(int i = 0; i < inventory.size(); i++) { if(inventory.get(i).name.equals(itemName)) { return i; } } return 999; } public boolean canObtainItem(Entity item) { int i = searchItemInInventory(item.name); try { if(item.stackable) { if(i != 999) { inventory.get(i).amt++; return true; } else if(inventory.size() != maxInvSize) { inventory.add((Entity) Class.forName(item.getClass().getName()).getDeclaredConstructor(GamePanel.class).newInstance(panel)); return true; } } else if(inventory.size() != maxInvSize) { inventory.add((Entity) Class.forName(item.getClass().getName()).getDeclaredConstructor(GamePanel.class).newInstance(panel)); return true; } } catch(ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } return false; } @Override public void invincibleCounting() { if(!invincible) return; invincibleCount++; if(invincibleCount > 60) { invincible = false; invincibleCount = 0; } } }