#include "Player.h" #include "Game.h" #include "PlayerHand.h" #include "ItemFilter.h" Player::Player(Framework::Vec3 location, int dimensionId, int entityId) : Entity(PlayerEntityType::INSTANCE, location, dimensionId, entityId), BasicShapedCrafter(3, 3, this) { for (int i = 0; i < 10; i++) { ItemSlot* slot = new ItemSlot("ItemBar", 50, 0, i, 0, ANY_DIRECTION, 0); itemBar.add(slot); addSlot(slot); } for (int i = 0; i < 30; i++) { ItemSlot* slot = new ItemSlot("Inventory", 50, 0, i + 10, 0, ANY_DIRECTION, 0); addSlot(slot); } leftHandPosition = 0; maxHP = 10; currentHP = 10; stamina = 10; maxStamina = 10; hunger = 10; maxHunger = 10; thirst = 10; maxThirst = 10; keyState = 0; jumping = 0; faceOffset = { 0.f, 0.f, 1.5f }; targetDistanceLimit = 4; } void Player::afterPullStack(ItemSlot* zSlot, Direction dir, const Item* zItem, int count) { for (auto slot : itemBar) { if (slot == zSlot) { needUpdate = 1; return; } } } void Player::afterPushStack(ItemSlot* zSlot, Direction dir, const Item* zItem, int count) { for (auto slot : itemBar) { if (slot == zSlot) { needUpdate = 1; return; } } } Framework::Text Player::getInventoryUIML() { Framework::Text result = ""; result += ""; result += ""; result += ""; result += ""; return result; } void Player::useItemSlot(ItemSlot* zSlot) { if (zSlot->zStack()) { ItemStack* stack = takeItemsOut(zSlot, 1, NO_DIRECTION); if (stack) { Item* item = stack->extractFromStack(); Entity::useItem(item->zItemType(), item); if (item->getDurability() > 0 && item->getDamage() < item->getMaxDamage()) { // put used item back stack->addToStack(item); // TODO: use inventory wrapper to update the cache of the inventory if (!zSlot->numberOfAddableItems(stack, NO_DIRECTION)) { // move other items to other space ItemStack* oldItems = zSlot->takeItemsOut(zSlot->zStack()->getSize(), NO_DIRECTION); zSlot->addItems(stack, NO_DIRECTION); addItems(oldItems, NO_DIRECTION); if (oldItems->getSize() > 0) { // TODO: drop remaining items } } else zSlot->addItems(stack, NO_DIRECTION); } else { // item is broken // move other items of the same type to the slot Array< ItemSlot*> fromSlots; for (ItemSlot* slot : itemBar) { if (slot != zSlot) fromSlots.add(slot); } Array targetSlots; targetSlots.add(zSlot); TypeItemFilter filter(item->zItemType()); localTransaction(&fromSlots, &targetSlots, &filter, zSlot->getFreeSpace(), NO_DIRECTION, NO_DIRECTION); // place broken item in inventory const ItemType* brokenType = item->zItemType()->zBrokenItemType(); if (brokenType) { Item* broken = item->zItemType()->breakItem(item); if (broken) { stack->addToStack(broken); addItems(stack, NO_DIRECTION); if (stack->getSize() > 0) { // TODO: drop remaining items } } } item->release(); } stack->release(); } } else Entity::useItem(PlayerHandItemType::INSTANCE, 0); // hand usage } void Player::setName(Framework::Text name) { this->name = name; } const char* Player::getName() const { return name; } void Player::tick(const Dimension* zDimension) { speed = { 0, 0, speed.z }; if ((keyState | Key::MOVE_FRONT) == keyState) speed += {faceDir.x, faceDir.y, 0}; if ((keyState | Key::MOVE_BACK) == keyState) speed += {-faceDir.x, -faceDir.y, 0}; if ((keyState | Key::MOVE_RIGHT) == keyState) { Vec2 norm = { faceDir.x, faceDir.y }; norm.CW90().normalize(); speed += {norm.x, norm.y, 0}; } if ((keyState | Key::MOVE_LEFT) == keyState) { Vec2 norm = { faceDir.x, faceDir.y }; norm.CCW90().normalize(); speed += {norm.x, norm.y, 0}; } Vec2 norm = { speed.x, speed.y }; if (norm.getLengthSq() != 0) { norm.normalize(); speed.x = norm.x * 4.f; // 4 blocks per second movement speed speed.y = norm.y * 4.f; } if ((keyState | Key::MOVE_DOWN) == keyState && gravityMultiplier == 0.f) speed.z = -4.f; if ((keyState | Key::LEFT_HAND_ACTION) == keyState) useItemSlot(itemBar.get(leftHandPosition)); if ((keyState | Key::RIGHT_HAND_ACTION) == keyState) useItemSlot(itemBar.get((leftHandPosition + 1) % itemBar.getEintragAnzahl())); return Entity::tick(zDimension); } void Player::playerApi(Framework::StreamReader* zRequest, NetworkResponse* zResponse) { char byte; zRequest->lese(&byte, 1); switch (byte) { case 0: // stop action zRequest->lese(&byte, 1); switch (byte) { case 0: keyState = keyState & ~Key::MOVE_FRONT; break; case 1: keyState = keyState & ~Key::MOVE_LEFT; break; case 2: keyState = keyState & ~Key::MOVE_BACK; break; case 3: keyState = keyState & ~Key::MOVE_RIGHT; break; case 4: if (gravityMultiplier == 0.f) speed.z = 0; keyState = keyState & ~Key::MOVE_DOWN; break; case 5: keyState = keyState & ~Key::ROTATE_LEFT; break; case 6: keyState = keyState & ~Key::ROTATE_RIGHT; break; case 7: if (gravityMultiplier == 0.f) speed.z = 0; keyState = keyState & ~Key::MOVE_UP; break; case 8: keyState = keyState & ~Key::LEFT_HAND_ACTION; break; case 9: keyState = keyState & ~Key::RIGHT_HAND_ACTION; break; } break; case 1: // begin action zRequest->lese(&byte, 1); switch (byte) { case 0: keyState = keyState | Key::MOVE_FRONT; break; case 1: keyState = keyState | Key::MOVE_LEFT; break; case 2: keyState = keyState | Key::MOVE_BACK; break; case 3: keyState = keyState | Key::MOVE_RIGHT; break; case 4: keyState = keyState | Key::MOVE_DOWN; break; case 5: keyState = keyState | Key::ROTATE_LEFT; break; case 6: keyState = keyState | Key::ROTATE_RIGHT; break; case 7: if ((keyState | Key::MOVE_UP) != keyState) { if (gravityMultiplier > 0) { if (jumping) { // TODO: check if flight is enabled gravityMultiplier = 0; jumping = 0; speed.z = 1.5f; } else { jumping = 1; speed.z = 5.f; } } else speed.z = 1.5f; } keyState = keyState | Key::MOVE_UP; break; case 8: keyState = keyState | Key::LEFT_HAND_ACTION; break; case 9: keyState = keyState | Key::RIGHT_HAND_ACTION; break; } break; case 2: // switch target direction zRequest->lese((char*)&faceDir.x, 4); zRequest->lese((char*)&faceDir.y, 4); zRequest->lese((char*)&faceDir.z, 4); break; case 3: // switch item bar position zRequest->lese((char*)&leftHandPosition, 4); leftHandPosition = leftHandPosition % itemBar.getEintragAnzahl(); needUpdate = 1; break; case 4: { // open inventory zResponse->openDialog("player_inventory"); Text uiml = getInventoryUIML(); int msgSize = 5 + uiml.getLength(); char* msg = new char[msgSize]; msg[0] = 0; // open dialog *(int*)(msg + 1) = uiml.getLength(); memcpy(msg + 5, uiml.getText(), uiml.getLength()); zResponse->setMessage(msg, msgSize, 1); break; } } } void Player::onFall(float collisionSpeed) { Entity::onFall(collisionSpeed); gravityMultiplier = 1.f; jumping = 0; } PlayerEntityType::PlayerEntityType() : EntityType(ID, ModelInfo("player", "player.ltdb/player.png", 6)) {} void PlayerEntityType::loadSuperEntity(Entity* zEntity, Framework::StreamReader* zReader) const { Player* zPlayer = dynamic_cast(zEntity); if (!zPlayer) throw "PlayerEntityType::loadSuperEntity was called with an entity witch is not an instance of Player"; zReader->lese((char*)&zPlayer->leftHandPosition, 4); EntityType::loadSuperEntity(zPlayer, zReader); } void PlayerEntityType::saveSuperEntity(Entity* zEntity, Framework::StreamWriter* zWriter) const { Player* zPlayer = dynamic_cast(zEntity); if (!zPlayer) throw "PlayerEntityType::saveSuperEntity was called with an entity witch is not an instance of Player"; zWriter->schreibe((char*)&zPlayer->leftHandPosition, 4); EntityType::saveSuperEntity(zEntity, zWriter); } Entity* PlayerEntityType::createEntity(Framework::Vec3 position, int dimensionId, int entityId) const { return new Player(position, dimensionId, entityId); }