#include "Player.h" #include "ArrayUtils.h" #include "BasicBlocks.h" #include "Block.h" #include "Chat.h" #include "Game.h" #include "ItemFilter.h" #include "ItemStack.h" #include "ItemType.h" #include "QuestDialog.h" #include "UIController.h" #include "UIMLBuilder.h" Player::Player(Framework::Vec3 location, int dimensionId, int entityId) : Entity(EntityTypeEnum::PLAYER, location, dimensionId, entityId), BasicShapedCrafter(3, 3, this, "inventory") { 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; maxStamina = 10; maxHunger = 10; maxThirst = 10; setHP(0, 0, 0, 10.f); setStamina(10); setHunger(10); setThirst(10); setJumpSpeed(5.f); keyState = 0; jumping = 0; faceOffset = {0.f, 0.f, 1.5f}; targetDistanceLimit = 4; maxMovementSpeed = 1.f; movementFlags |= MovementFlags::ROTATE_TO_FACE; } void Player::onTargetChange() { NetworkMessage* msg = new NetworkMessage(); ActionTarget::toMessage(zTarget(), dimensionId, msg); Game::INSTANCE->sendMessage(msg, this); } Framework::XML::Element* Player::getInventoryUIML() const { return UIMLBuilder::createDialog("player_inventory") ->setTitle("Inventory") ->setWidth(610) ->setHeight(450) ->addElement(UIMLBuilder::createCraftingGrid() ->setID("crafting") ->setMarginTop(9) ->setAlignTopStart() ->setAlignLeftStart() ->setMarginLeft(9) ->setWidth(282) ->setHeight(172) ->setRows(3) ->setColumns(3) ->setOutputSize(1) ->setEntitySource(getId()) ->build()) ->addElement(UIMLBuilder::createInventory() ->setID("inventory") ->setMarginBottom(18) ->setAlignBottomToElement("item_bar") ->setAlignLeftStart() ->setMarginLeft(9) ->setWidth(592) ->setHeight(172) ->setRowSize(10) ->setSlotCount(30) ->setSlotNameFilter("Inventory") ->setEntitySource(getId()) ->build()) ->addElement(UIMLBuilder::createInventory() ->setID("item_bar") ->setMarginBottom(9) ->setAlignBottomEnd() ->setAlignLeftStart() ->setMarginLeft(9) ->setWidth(592) ->setHeight(52) ->setRowSize(10) ->setSlotCount(10) ->setSlotNameFilter("ItemBar") ->setEntitySource(getId()) ->build()) ->build(); } Framework::XML::Element* Player::getPlayerGUI() const { return UIMLBuilder::createContainer() ->setID("player_gui") ->addChild(UIMLBuilder::createItemBar() ->setID("gui_item_bar") ->setMarginBottom(9) ->setAlignBottomEnd() ->setAlignLeftCenter() ->setWidth(592) ->setHeight(52) ->setRowSize(10) ->setSlotNameFilter("ItemBar") ->setEntitySource(getId()) ->build()) ->addChild(UIMLBuilder::createStatusBars() ->setID("gui_status_bars") ->setMarginBottom(9) ->setAlignBottomToElement("gui_item_bar") ->setAlignLeftCenter() ->setEntitySource(getId()) ->build()) ->build(); } void Player::useItemSlot(ItemSlot* zSlot, bool left) { if (Entity::useItem(zSlot->zStack() && zSlot->zStack()->zItem() ? zSlot->zStack()->zItem()->getTypeId() : ItemTypeEnum::PLAYER_HAND, (ItemStack*)zSlot->zStack(), left)) { zSlot->update(); if (zSlot->zStack()) { if (zSlot->zStack()->zItem()->getDurability() <= 0) { ItemStack* stack = zSlot->takeItemsOut( zSlot->getNumberOfItems(), NO_DIRECTION); Item* broken = stack->zItem()->zItemType()->breakItem(stack->zItem()); if (broken) { ItemStack* newStack = new ItemStack(broken, stack->getSize()); zSlot->addItems(newStack, NO_DIRECTION); if (newStack->getSize() > 0) { Game::INSTANCE->spawnItem( getLocation(), getDimensionId(), newStack); } else { newStack->release(); } } stack->release(); } else if (zSlot->zStack()->zItem()->getHp() <= 0) { ItemStack* stack = zSlot->takeItemsOut( zSlot->getNumberOfItems(), NO_DIRECTION); Framework::Array fromSlots; for (ItemSlot* slot : *this) { if (slot != zSlot) fromSlots.add(slot); } Framework::Array targetSlots; targetSlots.add(zSlot); TypeItemFilter filter; filter.setType(stack->zItem()->zItemType()); localTransaction(&fromSlots, &targetSlots, &filter, zSlot->getFreeSpace(), NO_DIRECTION, NO_DIRECTION); stack->release(); } } updateSlot(zSlot); } } void Player::setName(Framework::Text name) { this->name = name; } const char* Player::getName() const { return name; } void Player::tick(const Dimension* zDimension, double seconds) { if ((keyState | Key::LEFT_HAND_ACTION) == keyState) useItemSlot(itemBar.get(leftHandPosition), true); if ((keyState | Key::RIGHT_HAND_ACTION) == keyState) useItemSlot(itemBar.get(leftHandPosition), false); return Entity::tick(zDimension, seconds); } void Player::playerApi( Framework::StreamReader* zRequest, NetworkMessage* zResponse) { char byte; zRequest->lese(&byte, 1); switch (byte) { case 0: // stop action zRequest->lese(&byte, 1); switch (byte) { 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 8: keyState = keyState | Key::LEFT_HAND_ACTION; break; case 9: keyState = keyState | Key::RIGHT_HAND_ACTION; break; } break; case 2: // set face direction { zRequest->lese((char*)&faceDir.x, 4); zRequest->lese((char*)&faceDir.y, 4); zRequest->lese((char*)&faceDir.z, 4); // TODO: calculate rotation and try to rotate without collision calculateTarget( !itemBar.get(leftHandPosition)->isEmpty() ? itemBar.get(leftHandPosition)->zStack()->zItem() : 0); break; } case 3: { // switch item bar position zRequest->lese((char*)&leftHandPosition, 4); leftHandPosition = leftHandPosition % itemBar.getEintragAnzahl(); NetworkMessage* msg = new NetworkMessage(); msg->addressUIElement("gui_item_bar", -1); char* message = new char[5]; message[0] = 3; // set selected slot *(int*)(message + 1) = leftHandPosition; msg->setMessage(message, 5); Game::INSTANCE->sendMessage(msg, this); break; } case 4: { Game::INSTANCE->zUIController()->addDialog( new UIDialog("player_inventory", getId(), getInventoryUIML())); break; } case 5: { // request gui Framework::XML::Element* element = getPlayerGUI(); Framework::Text uiml = element->toString(); element->release(); int msgSize = 6 + uiml.getLength(); char* msg = new char[msgSize]; msg[0] = 2; // gui message msg[1] = 2; // set gui *(int*)(msg + 2) = uiml.getLength(); memcpy(msg + 6, uiml.getText(), uiml.getLength()); zResponse->setMessage(msg, msgSize); break; } case 6: { // inventory transaction bool isEntity; zRequest->lese((char*)&isEntity, 1); Inventory* source; if (isEntity) { int id; zRequest->lese((char*)&id, 4); source = Game::INSTANCE->zEntity(id, dimensionId); } else { int dim; Framework::Vec3 pos; zRequest->lese((char*)&dim, 4); zRequest->lese((char*)&pos.x, 4); zRequest->lese((char*)&pos.y, 4); zRequest->lese((char*)&pos.z, 4); source = Game::INSTANCE->zBlockAt(pos, dim, 0); } int sourceSlotId; zRequest->lese((char*)&sourceSlotId, 4); zRequest->lese((char*)&isEntity, 1); Inventory* target; if (isEntity) { int id; zRequest->lese((char*)&id, 4); target = Game::INSTANCE->zEntity(id, dimensionId); } else { int dim; Framework::Vec3 pos; zRequest->lese((char*)&dim, 4); zRequest->lese((char*)&pos.x, 4); zRequest->lese((char*)&pos.y, 4); zRequest->lese((char*)&pos.z, 4); target = Game::INSTANCE->zBlockAt(pos, dim, 0); } if (source && target) { int targetSlotId; zRequest->lese((char*)&targetSlotId, 4); SpecificSlotFilter filter(sourceSlotId, targetSlotId); source->interactWith(target, Direction::NO_DIRECTION) .pushItems(source->zSlot(sourceSlotId)->getNumberOfItems(), &filter); } break; } case 7: // craft action { bool isEntity; zRequest->lese((char*)&isEntity, 1); BasicShapedCrafter* target; if (isEntity) { int id; zRequest->lese((char*)&id, 4); target = dynamic_cast( Game::INSTANCE->zEntity(id, dimensionId)); if (target) target->applyCurrentRecipie(); } else { int dim; Framework::Vec3 pos; zRequest->lese((char*)&dim, 4); zRequest->lese((char*)&pos.x, 4); zRequest->lese((char*)&pos.y, 4); zRequest->lese((char*)&pos.z, 4); target = dynamic_cast( Game::INSTANCE->zRealBlockInstance(pos, dim)); if (target) { target->applyCurrentRecipie(); } else { BasicBlock* block = dynamic_cast( Game::INSTANCE->zRealBlockInstance(pos, dim)); if (block) { int index; zRequest->lese((char*)&index, 4); block->zComponent(index); target = dynamic_cast(block); if (target) { target->applyCurrentRecipie(); } } } } break; } case 8: // request left hand position { NetworkMessage* msg = new NetworkMessage(); msg->addressUIElement("gui_item_bar", -1); char* message = new char[5]; message[0] = 3; // set selected slot *(int*)(message + 1) = leftHandPosition; msg->setMessage(message, 5); Game::INSTANCE->sendMessage(msg, this); break; } case 9: // open quest dialog { Game::INSTANCE->zUIController()->addDialog( new QuestDialog(getId())); break; } case 10: // change movement flags { int flags; zRequest->lese((char*)&flags, 4); flags &= 0xFFF; // only lower 12 bits are valid flags |= movementFlags & 0xFFFFF000; movementFlags = flags; break; } } } void Player::onFall(float collisionSpeed) { Entity::onFall(collisionSpeed); // TODO: check validity } void Player::onDeath(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill) { this->setHP(zActor, zUsedItem, zUsedSkill, this->getMaxHP()); Game::INSTANCE->zChat()->broadcastMessage( name + " died!", Chat::CHANNEL_INFO); // TODO: respown } PlayerEntityType::PlayerEntityType() : EntityType() { setName("Player"); setModel(new ModelInfo("data/models/entities.m3/player", toArray("data/textures/entities.ltdb/player.png", 6), 0, 1.f)); } 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); char len; zReader->lese(&len, 1); char* name = new char[(int)len + 1]; zReader->lese(name, (int)len); name[(int)len] = 0; zPlayer->name = name; delete[] name; 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); char len = (char)Framework::textLength(zPlayer->getName()); zWriter->schreibe(&len, 1); zWriter->schreibe(zPlayer->getName(), (int)len); EntityType::saveSuperEntity(zEntity, zWriter); } Entity* PlayerEntityType::createEntity( Framework::Vec3 position, int dimensionId, int entityId) const { return new Player(position, dimensionId, entityId); }