diff --git a/assets/items/Tools.items b/assets/items/Tools.items index 3e6a0f3..c9c061d 100644 --- a/assets/items/Tools.items +++ b/assets/items/Tools.items @@ -11,7 +11,8 @@ + attackDuration="0.2" + energyCost="1" /> @@ -25,7 +26,8 @@ + attackDuration="0.2" + energyCost="1" /> diff --git a/assets/items/Weapons.items b/assets/items/Weapons.items index c994fbf..7982c2a 100644 --- a/assets/items/Weapons.items +++ b/assets/items/Weapons.items @@ -11,7 +11,8 @@ + attackDuration="0.4" + energyCost="1.5" /> @@ -24,7 +25,8 @@ + attackDuration="0.4" + energyCost="0.9" /> \ No newline at end of file diff --git a/assets/scenes/Game.scene b/assets/scenes/Game.scene index 29c1821..f10be84 100644 --- a/assets/scenes/Game.scene +++ b/assets/scenes/Game.scene @@ -26,12 +26,10 @@ - - - - - - + + diff --git a/src/components/basic/Inventory.cpp b/src/components/basic/Inventory.cpp new file mode 100644 index 0000000..6bb68c9 --- /dev/null +++ b/src/components/basic/Inventory.cpp @@ -0,0 +1,148 @@ +/* + * Inventory.cpp + * + * Created on: Dec 11, 2016 + * Author: tibi + */ + +#include +#include +#include + +namespace farmlands { +namespace components { +namespace basic { + +Inventory::Inventory() + : m_capacity(10), + m_items(nullptr) +{ +} + +Inventory::~Inventory() +{ + delete[] m_items; +} + +model::Component* Inventory::clone() +{ + Inventory* clone = new Inventory(); + clone->m_capacity = m_capacity; + return clone; +} + +void Inventory::dump(unsigned level) +{ + for (unsigned i = 0; i < level; i++) + std::cout<<" "; + + std::cout << " .Component: Inventory capacity=" << m_capacity << "\n"; +} + +void Inventory::onCreate() +{ + // Allocate items array + m_items = new model::GameObject*[m_capacity]; + memset(m_items, 0, sizeof(m_items[0]) * m_capacity); + + // Find all children + for (auto it = gameObject->childrenBegin(); it != gameObject->childrenEnd(); it++) + { + InventoryItem* item = (*it)->component(); + if (item) + { + Assert(item->slot >= 0 && item->slot < m_capacity, "Inventory item slot out of range."); + Assert(m_items[item->slot] == nullptr, "Multiple items on one slot."); + + m_items[item->slot] = *it; + } + } +} + +bool Inventory::add(model::GameObject* item) +{ + Assert(m_items != nullptr, "Inventory not initialized"); + Assert(item != nullptr, "Cannot add null object."); + + // Find an empty slot + size_t slot = (size_t)-1; + for (size_t i = 0; i < m_capacity; i++) + if (m_items[i] == nullptr) + { + slot = i; + break; + } + + if (slot != (size_t)-1) + { + set(slot, item); + return true; + } + return false; +} + +void Inventory::remove(size_t slot) +{ + Assert(m_items != nullptr, "Inventory not initialized."); + Assert(slot < m_capacity, "Slot out of range."); + + if (m_items[slot] != nullptr) + { + m_items[slot]->removeComponent(); + m_items[slot] = nullptr; + } +} + +void Inventory::set(size_t slot, model::GameObject* item) +{ + Assert(m_items != nullptr, "Inventory not initialized."); + Assert(slot < m_capacity, "Slot out of range."); + Assert(item != nullptr, "Cannot set null element."); + + remove(slot); + m_items[slot] = item; + + // Update InventoryItem + if (!item->haveComponent()) + item->addComponent(new InventoryItem); + + InventoryItem* invItem = item->component(); + invItem->slot = slot; +} + +model::GameObject* Inventory::get(size_t slot) +{ + Assert(m_items != nullptr, "Inventory not initialized."); + Assert(slot < m_capacity, "Slot out of range."); + + return m_items[slot]; +} + +void Inventory::setCapacity(size_t capacity) +{ + if (m_items != nullptr) + { + // Remove extra items + for (size_t i = m_capacity; i < capacity; i++) + remove(i); + + // Reallocate + model::GameObject** old = m_items; + m_items = new model::GameObject*[capacity]; + memset(m_items, 0, sizeof(m_items[0]) * capacity); + + // Copy old objects + for (size_t i = 0; i < std::min(m_capacity, capacity); i++) + m_items[i] = old[i]; + + // Finish + delete[] old; + } + + m_capacity = capacity; +} + +} /* namespace basic */ +} /* namespace components */ +} /* namespace farmlands */ + diff --git a/src/components/basic/Inventory.h b/src/components/basic/Inventory.h new file mode 100644 index 0000000..b363388 --- /dev/null +++ b/src/components/basic/Inventory.h @@ -0,0 +1,77 @@ +/* + * Inventory.h + * + * Created on: Dec 11, 2016 + * Author: tibi + */ + +#ifndef COMPONENTS_INVENTORY_INVENTORY_H_ +#define COMPONENTS_INVENTORY_INVENTORY_H_ + +#include +#include + +namespace farmlands { +namespace components { +namespace basic { + + class Inventory: public model::Component + { + public: + Inventory(); + virtual ~Inventory(); + + virtual model::Component* clone() override; + virtual void dump(unsigned level) override; + + virtual void onCreate() override; + + // Inventory management + /** + * Adds a game object to first available slot. + * Game object should be already added as a child of the parent game object. + * If object doesn't have an "InventoryItem" component, it will be added. + * @returns true if added successfully, false if no empty slot was found. + */ + bool add(model::GameObject* item); + + /** + * Removes the game object from the given slot. + * Doesn't delete/destroy the game object from the parent game object. + * Destroys the "InventoryItem" component of the object. + */ + void remove(size_t slot); + + /** + * Sets the given game object (which should be a child of the parent game object) to have the given slot. + * If there is an item in that slot, it is removed. + */ + void set(size_t slot, model::GameObject* item); + + /** + * Gets the game object in the given slot. + * Returns null if slot is empty. + */ + model::GameObject* get(size_t slot); + + /** + * Modifies the capacity of the inventory. + * If the inventory is already initialized, objects might be removed. + */ + void setCapacity(size_t capacity); + + /** + * Gets the capacity + */ + size_t capacity() const { return m_capacity; } + + private: + size_t m_capacity; + model::GameObject** m_items; + }; + +} /* namespace basic */ +} /* namespace components */ +} /* namespace farmlands */ + +#endif /* COMPONENTS_INVENTORY_INVENTORY_H_ */ diff --git a/src/components/basic/InventoryItem.cpp b/src/components/basic/InventoryItem.cpp new file mode 100644 index 0000000..2159ecf --- /dev/null +++ b/src/components/basic/InventoryItem.cpp @@ -0,0 +1,36 @@ +/* + * InventoryItem.cpp + * + * Created on: Dec 11, 2016 + * Author: tibi + */ + +#include +#include + +namespace farmlands { +namespace components { +namespace basic { + +InventoryItem::~InventoryItem() +{ +} + +model::Component* InventoryItem::clone() +{ + InventoryItem* item = new InventoryItem(); + item->slot = slot; + return item; +} + +void InventoryItem::dump(unsigned level) +{ + for (unsigned i = 0; i < level; i++) + std::cout<<" "; + + std::cout << " .Component: InventoryItem slot=" << slot << "\n"; +} + +} /* namespace basic */ +} /* namespace components */ +} /* namespace farmlands */ diff --git a/src/components/basic/InventoryItem.h b/src/components/basic/InventoryItem.h new file mode 100644 index 0000000..05bac11 --- /dev/null +++ b/src/components/basic/InventoryItem.h @@ -0,0 +1,32 @@ +/* + * InventoryItem.h + * + * Created on: Dec 11, 2016 + * Author: tibi + */ + +#ifndef COMPONENTS_INVENTORY_INVENTORYITEM_H_ +#define COMPONENTS_INVENTORY_INVENTORYITEM_H_ + +#include + +namespace farmlands { +namespace components { +namespace basic { + + class InventoryItem: public model::Component + { + public: + virtual ~InventoryItem(); + + virtual model::Component* clone() override; + virtual void dump(unsigned level) override; + + size_t slot; + }; + +} /* namespace basic */ +} /* namespace components */ +} /* namespace farmlands */ + +#endif /* COMPONENTS_INVENTORY_INVENTORYITEM_H_ */ diff --git a/src/components/items/Axe.cpp b/src/components/items/Axe.cpp index c333375..1806985 100644 --- a/src/components/items/Axe.cpp +++ b/src/components/items/Axe.cpp @@ -34,7 +34,7 @@ void Axe::dump(unsigned level) std::cout << " .Component: Axe\n"; } -void Axe::performAction(float x, float y, model::Direction d) +void Axe::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { } diff --git a/src/components/items/Axe.h b/src/components/items/Axe.h index 7f6f4cc..267b036 100644 --- a/src/components/items/Axe.h +++ b/src/components/items/Axe.h @@ -8,14 +8,14 @@ #ifndef COMPONENTS_ITEMS_AXE_H_ #define COMPONENTS_ITEMS_AXE_H_ -#include +#include #include namespace farmlands { namespace components { namespace items { - class Axe: public model::Component, public IPlayerAction + class Axe: public model::Component, public model::IPlayerAction { public: Axe(); @@ -24,7 +24,7 @@ namespace items { virtual model::Component* clone() override; virtual void dump(unsigned level) override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; }; } /* namespace items */ diff --git a/src/components/items/Giftable.cpp b/src/components/items/Giftable.cpp index e876356..e14b6f9 100644 --- a/src/components/items/Giftable.cpp +++ b/src/components/items/Giftable.cpp @@ -26,7 +26,7 @@ model::Component* Giftable::clone() return new Giftable(); } -void Giftable::performAction(float x, float y, model::Direction d) +void Giftable::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { } diff --git a/src/components/items/Giftable.h b/src/components/items/Giftable.h index efec8c2..507d03e 100644 --- a/src/components/items/Giftable.h +++ b/src/components/items/Giftable.h @@ -8,14 +8,14 @@ #ifndef CONTROLLER_ITEMS_GIFTABLE_H_ #define CONTROLLER_ITEMS_GIFTABLE_H_ -#include +#include #include namespace farmlands { namespace components { namespace items { - class Giftable: public model::Component, public IPlayerAction + class Giftable: public model::Component, public model::IPlayerAction { public: Giftable(); @@ -24,7 +24,7 @@ namespace items { virtual model::Component* clone() override; virtual void dump(unsigned level) override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; }; } /* namespace items */ diff --git a/src/components/items/Hoe.cpp b/src/components/items/Hoe.cpp index 1b86c34..2bbe8cc 100644 --- a/src/components/items/Hoe.cpp +++ b/src/components/items/Hoe.cpp @@ -53,16 +53,13 @@ void Hoe::onInitialize() m_map = (*it)->component(); } -void Hoe::performAction(float x, float y, model::Direction d) +void Hoe::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { Assert(m_map, "No background object!!!"); // Compute watering position - float digX, digY; - translate(x, y, d, 0.5f, &digX, &digY); - - size_t col = floorf(digX); - size_t row = floorf(digY); + size_t col = floorf(lookX); + size_t row = floorf(lookY); // See what the cell contains Cell backCell = m_map->layer(0).get(row, col); diff --git a/src/components/items/Hoe.h b/src/components/items/Hoe.h index ccfcf0e..8b5e6fa 100644 --- a/src/components/items/Hoe.h +++ b/src/components/items/Hoe.h @@ -8,7 +8,7 @@ #ifndef COMPONENTS_ITEMS_HOE_H_ #define COMPONENTS_ITEMS_HOE_H_ -#include +#include #include #include #include @@ -17,7 +17,7 @@ namespace farmlands { namespace components { namespace items { - class Hoe: public model::Component, public IPlayerAction + class Hoe: public model::Component, public model::IPlayerAction { public: Hoe(); @@ -28,7 +28,7 @@ namespace items { virtual void onInitialize() override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; private: Map* m_map; diff --git a/src/components/items/Pickaxe.cpp b/src/components/items/Pickaxe.cpp index fec5e25..2685294 100644 --- a/src/components/items/Pickaxe.cpp +++ b/src/components/items/Pickaxe.cpp @@ -34,7 +34,7 @@ void Pickaxe::dump(unsigned level) std::cout << " .Component: Pickaxe\n"; } -void Pickaxe::performAction(float x, float y, model::Direction d) +void Pickaxe::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { } diff --git a/src/components/items/Pickaxe.h b/src/components/items/Pickaxe.h index 1edeb99..e06d67d 100644 --- a/src/components/items/Pickaxe.h +++ b/src/components/items/Pickaxe.h @@ -8,14 +8,14 @@ #ifndef COMPONENTS_ITEMS_PICKAXE_H_ #define COMPONENTS_ITEMS_PICKAXE_H_ -#include +#include #include namespace farmlands { namespace components { namespace items { - class Pickaxe: public model::Component, public IPlayerAction + class Pickaxe: public model::Component, public model::IPlayerAction { public: Pickaxe(); @@ -24,7 +24,7 @@ namespace items { virtual model::Component* clone() override; virtual void dump(unsigned level) override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; }; } /* namespace items */ diff --git a/src/components/items/Scythe.cpp b/src/components/items/Scythe.cpp index 1255591..80fdf64 100644 --- a/src/components/items/Scythe.cpp +++ b/src/components/items/Scythe.cpp @@ -34,7 +34,7 @@ void Scythe::dump(unsigned level) std::cout << " .Component: Scythe\n"; } -void Scythe::performAction(float x, float y, model::Direction d) +void Scythe::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { } diff --git a/src/components/items/Scythe.h b/src/components/items/Scythe.h index 583626e..2181342 100644 --- a/src/components/items/Scythe.h +++ b/src/components/items/Scythe.h @@ -8,14 +8,14 @@ #ifndef COMPONENTS_ITEMS_SCYTHE_H_ #define COMPONENTS_ITEMS_SCYTHE_H_ -#include +#include #include namespace farmlands { namespace components { namespace items { - class Scythe: public model::Component, public IPlayerAction + class Scythe: public model::Component, public model::IPlayerAction { public: Scythe(); @@ -24,7 +24,7 @@ namespace items { virtual model::Component* clone() override; virtual void dump(unsigned level) override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; }; } /* namespace items */ diff --git a/src/components/items/WateringCan.cpp b/src/components/items/WateringCan.cpp index cdc7aed..eaf197f 100644 --- a/src/components/items/WateringCan.cpp +++ b/src/components/items/WateringCan.cpp @@ -23,7 +23,8 @@ namespace items { WateringCan::WateringCan() : capacity(10), amountLeft(10), - m_map(nullptr) + m_map(nullptr), + m_grid(nullptr) { } @@ -62,16 +63,13 @@ void WateringCan::onInitialize() m_grid = (*gridIt)->component(); } -void WateringCan::performAction(float x, float y, model::Direction d) +void WateringCan::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { Assert(m_map, "No background object!!!"); // Compute watering position - float digX, digY; - translate(x, y, d, 0.5f, &digX, &digY); - - size_t col = floorf(digX); - size_t row = floorf(digY); + size_t col = floorf(lookX); + size_t row = floorf(lookY); // See what the cell contains Cell backCell = m_map->layer(0).get(row, col); diff --git a/src/components/items/WateringCan.h b/src/components/items/WateringCan.h index c2c93f1..be8f926 100644 --- a/src/components/items/WateringCan.h +++ b/src/components/items/WateringCan.h @@ -9,7 +9,7 @@ #define COMPONENTS_ITEMS_WATERINGCAN_H_ #include -#include +#include #include #include #include @@ -18,7 +18,7 @@ namespace farmlands { namespace components { namespace items { - class WateringCan: public model::Component, public IPlayerAction + class WateringCan: public model::Component, public model::IPlayerAction { public: WateringCan(); @@ -29,7 +29,7 @@ namespace items { virtual void onInitialize() override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; void fillCan(); diff --git a/src/components/items/Weapon.cpp b/src/components/items/Weapon.cpp index 680b1d2..63cbe5b 100644 --- a/src/components/items/Weapon.cpp +++ b/src/components/items/Weapon.cpp @@ -20,6 +20,7 @@ Weapon::Weapon() critDamage(0), attackDuration(1.0f), attackTimeLeft(0), + energyCost(0), m_sprite(nullptr) { } @@ -57,12 +58,10 @@ void Weapon::onUpdateLogic() } } -void Weapon::performAction(float x, float y, model::Direction d) +void Weapon::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energCost) { - if (attackTimeLeft <= 0) - { - attackTimeLeft = attackDuration; - } + *timeCost = attackTimeLeft = attackDuration; + *energCost = energyCost; } void Weapon::dump(unsigned level) diff --git a/src/components/items/Weapon.h b/src/components/items/Weapon.h index b3e46a8..0b25d30 100644 --- a/src/components/items/Weapon.h +++ b/src/components/items/Weapon.h @@ -9,15 +9,15 @@ #define CONTROLLER_ITEMS_WEAPON_H_ #include -#include #include #include +#include namespace farmlands { namespace components { namespace items { - class Weapon: public model::Component, public IPlayerAction + class Weapon: public model::Component, public model::IPlayerAction { public: Weapon(); @@ -33,7 +33,7 @@ namespace items { /** * Performs everything required to attacking an enemy with a weapon. To be called from player controller. */ - virtual void performAction(float x, float y, model::Direction d); + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; // Properties float damage; @@ -43,6 +43,8 @@ namespace items { float attackDuration; // In seconds float attackTimeLeft; + float energyCost; + private: basic::Sprite* m_sprite; }; diff --git a/src/components/plants/Seed.cpp b/src/components/plants/Seed.cpp index 7fbe00f..7e4799c 100644 --- a/src/components/plants/Seed.cpp +++ b/src/components/plants/Seed.cpp @@ -70,14 +70,11 @@ void Seed::onInitialize() m_map = (*mapIt)->component(); } -void Seed::performAction(float x, float y, model::Direction d) +void Seed::performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) { // Compute planting position - float digX, digY; - translate(x, y, d, 0.5f, &digX, &digY); - - size_t col = floorf(digX); - size_t row = floorf(digY); + size_t col = floorf(lookX); + size_t row = floorf(lookY); // Soil is located on layer 1 Cell cell = m_map->layer(1).get(row, col); diff --git a/src/components/plants/Seed.h b/src/components/plants/Seed.h index c54e031..eaf892b 100644 --- a/src/components/plants/Seed.h +++ b/src/components/plants/Seed.h @@ -9,15 +9,15 @@ #define COMPONENTS_ITEMS_SEED_H_ #include -#include #include +#include #include namespace farmlands { namespace components { namespace plants { - class Seed: public model::Component, public items::IPlayerAction + class Seed: public model::Component, public model::IPlayerAction { public: Seed(); @@ -28,7 +28,7 @@ namespace plants { virtual void onInitialize() override; - virtual void performAction(float x, float y, model::Direction d) override; + virtual void performAction(float lookX, float lookY, float* timeCost, float* hpCost, float* energyCost) override; std::string plantName; diff --git a/src/components/player/Player.cpp b/src/components/player/Player.cpp new file mode 100644 index 0000000..8b3c78c --- /dev/null +++ b/src/components/player/Player.cpp @@ -0,0 +1,349 @@ +/* + * Player.cpp + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#include +#include +#include +#include + +#include + +using namespace farmlands::components::basic; +using namespace farmlands::components::items; +using namespace farmlands::graphics; +using namespace farmlands::input; +using namespace farmlands::model; + +namespace farmlands { +namespace components { +namespace player { + +static const float PlayerWalkVelocity = 2.0f; // The default velocity of the player when walking (units/sec). +static const float PlayerRunVelocity = 4.0f; // The default velocity of the player when running (units/sec). +static const float PlayerAttackVelocity = 0.1f; // Movement speed when attacking. + +/** + * Distance from player position to "look" position. + * This position is used for picking the cell which will be affected by the player's actions. + */ +static const float PlayerLookDistance = 0.5f; + +/** + * Map between velocity and direction. + */ +static const Direction VelocitySignDirections[3][3] = +{ + { Direction::NorthWest, Direction::West, Direction::SouthWest }, + { Direction::North, Direction::None, Direction::South }, + { Direction::NorthEast, Direction::East, Direction::SouthEast }, +}; + +Player::Player() + : selectedItemIndex(-1), + selectedItem(nullptr), + selectedWeapon(nullptr), + itemActionTimeLeft(0), + facingDirection(Direction::South), + walking(false), + running(false), + lookX(0), lookY(0), + hp(100), maxHp(100), + energy(100), maxEnergy(100), + money(0), + m_transform(nullptr), + m_inventory(nullptr), + m_grid(nullptr) +{ +} + +Player::~Player() +{ +} + +Component* Player::clone() +{ + Player* clone = new Player(); + + // Inventory + clone->selectedItemIndex = selectedItemIndex; + clone->itemActionTimeLeft = itemActionTimeLeft; + + // Movement + clone->facingDirection = facingDirection; + clone->walking = walking; + clone->running = running; + + // The position at which the player is looking + clone->lookX = lookX; + clone->lookY = lookY; + + // Health + clone->hp = hp; + clone->energy = energy; + + // Cash + clone->money = money; + + return clone; +} + +void Player::dump(unsigned level) +{ + for (unsigned i = 0; i < level; i++) + std::cout<<" "; + + std::cout << " .Component: Player\n"; +} + +void Player::onInitialize() +{ + m_transform = gameObject->component(); + m_inventory = gameObject->component(); + + // Search for the object which has the grid + auto root = &GameState::current().scene->root; + auto gridIt = root->findByComponent(); + Assert(gridIt != root->childrenEnd(), "Cannot find grid component."); + m_grid = (*gridIt)->component(); + + initializeInventory(); +} + +bool Player::onEvent(SDL_Event& event) +{ + handleInventoryDropEvent(event); + handleInventorySetEvent(event); + handleActionEvents(event); + + return false; +} + +void Player::onUpdateLogic() +{ + itemActionTimeLeft -= GameState::current().deltaTime; + hp = clamp(hp, 0, maxHp); + energy = clamp(energy, 0, maxEnergy); + + updateMovement(); +} + +void Player::onPreRender() +{ + preRenderSelectedItem(); + preRenderMovement(); +} + +void Player::initializeInventory() +{ + Assert(m_inventory != nullptr, "Inventory component is missing!"); + + // Get currently selected item + if (selectedItem >= 0 && selectedItemIndex < m_inventory->capacity()) + { + selectedItem = m_inventory->get(static_cast(selectedItemIndex)); + selectedWeapon = (selectedItem != nullptr) ? selectedItem->component() : nullptr; + } + + // Set enabled state of inventory items + for (size_t i = 0; i < m_inventory->capacity(); i++) + { + GameObject* obj = m_inventory->get(i); + if (obj) + { + obj->setEnabled(i == static_cast(selectedItemIndex)); + } + } +} + +void Player::handleInventoryDropEvent(SDL_Event& event) +{ + bool inventoryDrop = Input::instance().down(GameKey::InventoryDrop, event); + + if (inventoryDrop && selectedItemIndex >= 0) + { + // TODO: convert to 'pickable' item instead of destroying + m_inventory->remove(static_cast(selectedItemIndex)); + gameObject->destroyChild(selectedItem); + + selectedItemIndex = -1; + selectedItem = nullptr; + selectedWeapon = nullptr; + } +} + +void Player::handleInventorySetEvent(SDL_Event& event) +{ + // See what key was pressed + int slot = -1; + + if (Input::instance().down(GameKey::Inventory1, event)) slot = 0; + if (Input::instance().down(GameKey::Inventory2, event)) slot = 1; + if (Input::instance().down(GameKey::Inventory3, event)) slot = 2; + if (Input::instance().down(GameKey::Inventory4, event)) slot = 3; + if (Input::instance().down(GameKey::Inventory5, event)) slot = 4; + if (Input::instance().down(GameKey::Inventory6, event)) slot = 5; + if (Input::instance().down(GameKey::Inventory7, event)) slot = 6; + if (Input::instance().down(GameKey::Inventory8, event)) slot = 7; + if (Input::instance().down(GameKey::Inventory9, event)) slot = 8; + if (Input::instance().down(GameKey::Inventory10, event)) slot = 9; + + if (0 <= slot && slot < m_inventory->capacity()) + { + // Disable old object + if (selectedItem != nullptr) + selectedItem->setEnabled(false); + + // Obtain new object + selectedItemIndex = slot; + selectedItem = m_inventory->get(slot); + selectedWeapon = (selectedItem != nullptr) ? selectedItem->component() : nullptr; + + // Enable new object + if (selectedItem) + selectedItem->setEnabled(true); + } +} + +void Player::preRenderSelectedItem() +{ + // Set item position + if (selectedItem) + { + basic::Transform* itemTransf = selectedItem->component(); + + if (facingDirection & Direction::East) + { + itemTransf->x = 0.2f; + itemTransf->y = -0.8f; + } + else if (facingDirection & Direction::West) + { + itemTransf->x = -0.8f; + itemTransf->y = -0.8f; + } + } +} + +void Player::preRenderMovement() +{ + // Get sprite + Sprite* sprite = gameObject->component(); + + // Compute current state + std::string stateName = (walking) ? "Walking " : "Idle "; + + if (facingDirection & Direction::East) + stateName += "right"; + else if (facingDirection & Direction::West) + stateName += "left"; + else if (facingDirection & Direction::North) + stateName += "up"; + else + stateName += "down"; + + sprite->setState(stateName); + + // Set animation velocity + float animVelocity = (running) ? 1.0f : 0.7f; + if (itemActionTimeLeft > 0) + animVelocity = 0.1f; + // TODO: move this animation velocity change somewhere else + + sprite->animationVelocity = animVelocity; + + // Set camera + Transform* cam = GameState::current().renderContext.cameraTransform(); + cam->x = m_transform->x; + cam->y = m_transform->y - 1; +} + +void Player::updateMovement() +{ + running = Input::instance().pressed(GameKey::Run); + walking = false; + + // Compute movement velocity + float velMultiplier = PlayerWalkVelocity; + + if (itemActionTimeLeft > 0) + velMultiplier = PlayerAttackVelocity; + else if (running) + velMultiplier = PlayerRunVelocity; + + velMultiplier *= GameState::current().deltaTime; + + // Compute movement positions + float vx = Input::instance().getX() * velMultiplier; + float vy = Input::instance().getY() * velMultiplier; + float newX = m_transform->x + vx; + float newY = m_transform->y + vy; + + if ((vx || vy) && canMove(newX, newY)) + { + m_transform->x = newX; + m_transform->y = newY; + + walking = true; + facingDirection = getDirection(vx, vy); + + translate(newX, newY, facingDirection, PlayerLookDistance, &lookX, &lookY); + } +} + +Direction Player::getDirection(float vx, float vy) +{ + int xx = (0 < vx) - (vx < 0); + int yy = (0 < vy) - (vy < 0); + + return VelocitySignDirections[xx + 1][yy + 1]; +} + +void Player::handleActionEvents(SDL_Event& event) +{ + bool action1 = Input::instance().down(GameKey::Action, event); + bool action2 = Input::instance().down(GameKey::Action2, event); + + if (action1 && itemActionTimeLeft <= 0) + { + performAction(selectedItem); + } + + if (action2 && itemActionTimeLeft <= 0) + { + GameObject* obj = m_grid->get(lookX, lookY); + performAction(obj); + } +} + +void Player::performAction(model::GameObject* obj) +{ + if (obj == nullptr) + return; + + // Call components which implement ITool + for (auto it = obj->componentsBegin(); it != obj->componentsEnd(); it++) + { + IPlayerAction* action = dynamic_cast(it->second); + if (action != nullptr) + { + float timeCost = 0; + float hpCost = 0; + float energyCost = 0; + + action->performAction(lookX, lookY, &timeCost, &hpCost, &energyCost); + + itemActionTimeLeft += timeCost; + hp -= hpCost; + energy -= energyCost; + } + } +} + + +} /* namespace player */ +} /* namespace components */ +} /* namespace farmlands */ diff --git a/src/components/player/Player.h b/src/components/player/Player.h new file mode 100644 index 0000000..22e9ce2 --- /dev/null +++ b/src/components/player/Player.h @@ -0,0 +1,87 @@ +/* + * Player.h + * + * Created on: Dec 10, 2016 + * Author: tibi + */ + +#ifndef COMPONENTS_PLAYER_PLAYER_H_ +#define COMPONENTS_PLAYER_PLAYER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace farmlands { +namespace components { +namespace player { + + class Player: public model::Component + { + public: + Player(); + virtual ~Player(); + + virtual model::Component* clone() override; + virtual void dump(unsigned level) override; + + virtual void onInitialize() override; + virtual bool onEvent(SDL_Event& event) override; + virtual void onUpdateLogic() override; + virtual void onPreRender() override; + + // Inventory + int selectedItemIndex; + model::GameObject* selectedItem; + items::Weapon* selectedWeapon; + + float itemActionTimeLeft; + + // Movement + model::Direction facingDirection; + bool walking, running; + + // The position at which the player is looking + float lookX, lookY; + + // Health, energy + float hp, maxHp; + float energy, maxEnergy; + + // Cash + uint32_t money; + + private: + + // Inventory + void initializeInventory(); + void handleInventoryDropEvent(SDL_Event& event); + void handleInventorySetEvent(SDL_Event& event); + void preRenderSelectedItem(); + + // Movement + void preRenderMovement(); + void updateMovement(); + bool canMove(float x, float y) { return true; } + static model::Direction getDirection(float vx, float vy); + + // Actions + void handleActionEvents(SDL_Event& event); + void performAction(model::GameObject* obj); + + basic::Transform* m_transform; + basic::Inventory* m_inventory; + basic::Grid* m_grid; + }; + +} /* namespace player */ +} /* namespace components */ +} /* namespace farmlands */ + +#endif /* COMPONENTS_PLAYER_PLAYER_H_ */ diff --git a/src/components/player/PlayerInventory.cpp b/src/components/player/PlayerInventory.cpp deleted file mode 100644 index 9ba92bd..0000000 --- a/src/components/player/PlayerInventory.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * PlayerInventory.cpp - * - * Created on: Dec 3, 2016 - * Author: tibi - */ - -#include -#include -#include -#include -#include