Skip to content

Commit

Permalink
Potions and Elixers #492 (#496)
Browse files Browse the repository at this point in the history
* current addition of potion of healing. May include mana later.

* For issue #492 : Added potion.cpp/.h for cleaner code instead of jamming all the logic in the triggerItem function which would have gotten very ugly very quickly. Also added FullHealing as well as mana and rejuvination equivalents since they had related features.

* for #492, All potions and elixers added along with functions to add to attributes.

* Update player.cpp

* Update guimanager.cpp

* Update player.cpp

* added cases to satisfy the errors in appveyor

* Update guimanager.cpp

* Updated the add Attributes functions to use std::min()

* Updated functions to use FixedPoint

* Update potion.h

* Update guimanager.cpp

* Update potion.h

* Update guimanager.cpp

* Update potion.cpp

* Update potion.cpp

* Update playerinput.h

* Update playerinput.cpp

* Update playerbehaviour.cpp

* Update guimanager.cpp

* Update playerbehaviour.cpp

* Update CMakeLists.txt

* Update guimanager.cpp

* compile fixes

* clang-format

* changelog

Co-authored-by: neveza <[email protected]>
Co-authored-by: Tom Mason <[email protected]>
  • Loading branch information
3 people authored Jun 11, 2020
1 parent 99e184e commit 4ef76c1
Show file tree
Hide file tree
Showing 19 changed files with 290 additions and 6 deletions.
2 changes: 2 additions & 0 deletions apps/freeablo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ add_library(freeablo_lib # split into a library so I can link to it from tests
faworld/playerinput.h
faworld/position.cpp
faworld/position.h
faworld/potion.cpp
faworld/potion.h
faworld/storedata.cpp
faworld/storedata.h
faworld/target.cpp
Expand Down
7 changes: 7 additions & 0 deletions apps/freeablo/fagui/guimanager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "guimanager.h"
#include "../engine/enginemain.h"
#include "../engine/localinputhandler.h"
#include "../engine/threadmanager.h"
#include "../farender/renderer.h"
#include "../fasavegame/gameloader.h"
#include "../faworld/actorstats.h"
Expand All @@ -27,6 +28,7 @@
#include <memory>
#include <misc/misc.h>
#include <misc/stringops.h>
#include <random/random.h>
#include <render/spritegroup.h>
#include <serial/textstream.h>
#include <string>
Expand Down Expand Up @@ -184,6 +186,11 @@ namespace FAGui
mGoldSplitTarget = target;
mGoldSplitCnt = 0;
}
if (item->getAsUsableItem())
{
FAWorld::PlayerInput::UseItemData input{target};
Engine::EngineMain::get()->getLocalInputHandler()->addInput(FAWorld::PlayerInput(input, mPlayer->getId()));
}
}

void GuiManager::item(nk_context* ctx, FAWorld::EquipTarget target, RectOrVec2 placement, ItemHighlightInfo highlight, bool checkerboarded)
Expand Down
1 change: 1 addition & 0 deletions apps/freeablo/faworld/actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ namespace FAWorld
void Actor::heal(int32_t toHeal) { mStats.getHp().add(toHeal); }

void Actor::restoreMana() { mStats.getMana().current = mStats.getMana().max; }
void Actor::restoreMana(int32_t toRestore) { mStats.getMana().add(toRestore); }

void Actor::stopMoving(std::optional<Misc::Direction> direction) { mMoveHandler.stopMoving(*this, direction); }

Expand Down
1 change: 1 addition & 0 deletions apps/freeablo/faworld/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace FAWorld
void heal();
void heal(int32_t toHeal);
void restoreMana();
void restoreMana(int32_t toRestore);
void stopMoving(std::optional<Misc::Direction> direction = std::nullopt);
virtual void die();
bool isDead() const;
Expand Down
5 changes: 5 additions & 0 deletions apps/freeablo/faworld/actorstats.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ namespace FAWorld
int32_t dexterity = 0;
int32_t vitality = 0;

int32_t maxStrength = 0;
int32_t maxMagic = 0;
int32_t maxDexterity = 0;
int32_t maxVitality = 0;

bool operator==(const BaseStats& other)
{
return strength == other.strength && magic == other.magic && dexterity == other.dexterity && vitality == other.vitality;
Expand Down
2 changes: 1 addition & 1 deletion apps/freeablo/faworld/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ namespace FAWorld
case EquipTargetType::inventory:
break;
case EquipTargetType::belt:
ok = cursorItem->getAsMiscItem() && cursorItem->getAsMiscItem()->getBase()->isBeltEquippable();
ok = cursorItem->getAsUsableItem() && cursorItem->getAsUsableItem()->getBase()->isBeltEquippable();
break;
case EquipTargetType::head:
ok = cursorItem->getBase()->getEquipType() == ItemEquipType::head;
Expand Down
2 changes: 1 addition & 1 deletion apps/freeablo/faworld/item/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace FAWorld
virtual EquipmentItem* getAsEquipmentItem() { return nullptr; }
const EquipmentItem* getAsEquipmentItem() const { return const_cast<Item*>(this)->getAsEquipmentItem(); }
virtual UsableItem* getAsUsableItem() { return nullptr; }
const UsableItem* getAsMiscItem() const { return const_cast<Item*>(this)->getAsUsableItem(); }
const UsableItem* getAsUsableItem() const { return const_cast<Item*>(this)->getAsUsableItem(); }
virtual GoldItem* getAsGoldItem() { return nullptr; }
const GoldItem* getAsGoldItem() const { return const_cast<Item*>(this)->getAsGoldItem(); }

Expand Down
9 changes: 9 additions & 0 deletions apps/freeablo/faworld/item/usableitem.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
#include "usableitem.h"
#include "usableitembase.h"
#include <engine/threadmanager.h>
#include <misc/misc.h>

namespace FAWorld
{
UsableItem::UsableItem(const UsableItemBase* base) : super(base) {}

const UsableItemBase* UsableItem::getBase() const { return safe_downcast<const UsableItemBase*>(mBase); }

void UsableItem::applyEffect(Player& user)
{
if (!getBase()->mUseSoundPath.empty())
Engine::ThreadManager::get()->playSound(getBase()->mUseSoundPath);

getBase()->mEffect(user);
}
}
3 changes: 3 additions & 0 deletions apps/freeablo/faworld/item/usableitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace FAWorld
{
class UsableItemBase;
class Player;

class UsableItem final : public Item
{
Expand All @@ -17,6 +18,8 @@ namespace FAWorld

UsableItem* getAsUsableItem() override { return this; }

void applyEffect(Player& user);

const UsableItemBase* getBase() const;
};
}
88 changes: 87 additions & 1 deletion apps/freeablo/faworld/item/usableitembase.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,95 @@
#include "usableitembase.h"
#include <faworld/item/usableitem.h>
#include <faworld/potion.h>

namespace FAWorld
{
UsableItemBase::UsableItemBase(const DiabloExe::ExeItem& exeItem) : super(exeItem) {}
UsableItemBase::UsableItemBase(const DiabloExe::ExeItem& exeItem) : super(exeItem)
{
switch (exeItem.miscId)
{
case ItemMiscId::potionOfHealing:
{
mEffect = Potion::restoreHp;
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::potionOfFullHealing:
{
mEffect = Potion::restoreHpFull;
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::potionOfMana:
{
mEffect = Potion::restoreMana;
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::potionOfFullMana:
{
mEffect = Potion::restoreManaFull;
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::potionOfRejuvenation:
{
mEffect = [](Player& player) {
Potion::restoreHp(player);
Potion::restoreMana(player);
};
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::potionOfFullRejuvenation:
{
mEffect = [](Player& player) {
Potion::restoreHpFull(player);
Potion::restoreManaFull(player);
};
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::elixirOfDexterity:
{
mEffect = [](Player& player) { Potion::increaseDexterity(player, 1); };
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::elixirOfMagic:
{
mEffect = [](Player& player) { Potion::increaseMagic(player, 1); };
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::elixirOfVitality:
{
mEffect = [](Player& player) { Potion::increaseVitality(player, 1); };
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::elixirOfStrength:
{
mEffect = [](Player& player) { Potion::increaseStrength(player, 1); };
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
case ItemMiscId::spectralElixir:
{
mEffect = [](Player& player) {
Potion::increaseStrength(player, 3);
Potion::increaseVitality(player, 3);
Potion::increaseMagic(player, 3);
Potion::increaseDexterity(player, 3);
};
mUseSoundPath = "sfx/items/invpot.wav";
break;
}
default:
mEffect = [](Player&) {};
break;
}
}

bool UsableItemBase::isBeltEquippable() const { return mSize == Vec2i(1, 1); }

Expand Down
7 changes: 5 additions & 2 deletions apps/freeablo/faworld/item/usableitembase.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
#pragma once
#include "itembase.h"
#include <functional>

namespace FAWorld
{
class Player;

class UsableItemBase final : public ItemBase
{
using super = ItemBase;

public:
explicit UsableItemBase(const DiabloExe::ExeItem& exeItem);

std::unique_ptr<Item> createItem() const override;

bool isBeltEquippable() const;

public:
std::function<void(Player&)> mEffect;
std::string mUseSoundPath;
};
}
35 changes: 35 additions & 0 deletions apps/freeablo/faworld/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,36 @@ namespace FAWorld
{
mStats.initialise(initialiseActorStats(charStats));
mStats.mLevelXpCounts = charStats.mNextLevelExp;
switch (mPlayerClass)
{
// https://wheybags.gitlab.io/jarulfs-guide/#maximum-stats for max base stats numbers
case PlayerClass::warrior:
{
mStats.baseStats.maxStrength = 250;
mStats.baseStats.maxMagic = 50;
mStats.baseStats.maxDexterity = 60;
mStats.baseStats.maxVitality = 100;
break;
}
case PlayerClass::rogue:
{
mStats.baseStats.maxStrength = 50;
mStats.baseStats.maxMagic = 70;
mStats.baseStats.maxDexterity = 250;
mStats.baseStats.maxVitality = 80;
break;
}
case PlayerClass::sorceror:
{
mStats.baseStats.maxStrength = 45;
mStats.baseStats.maxMagic = 250;
mStats.baseStats.maxDexterity = 85;
mStats.baseStats.maxVitality = 80;
break;
}
case PlayerClass::none:
break;
}

mFaction = Faction::heaven();
mMoveHandler.mPathRateLimit = World::getTicksInPeriod("0.1"); // allow players to repath much more often than other actors
Expand Down Expand Up @@ -570,6 +600,11 @@ namespace FAWorld
restoreMana();
}

void Player::addStrength(int32_t delta) { mStats.baseStats.strength = std::min(mStats.baseStats.strength + delta, mStats.baseStats.maxStrength); }
void Player::addMagic(int32_t delta) { mStats.baseStats.magic = std::min(mStats.baseStats.magic + delta, mStats.baseStats.maxMagic); }
void Player::addDexterity(int32_t delta) { mStats.baseStats.dexterity = std::min(mStats.baseStats.dexterity + delta, mStats.baseStats.maxDexterity); }
void Player::addVitality(int32_t delta) { mStats.baseStats.vitality = std::min(mStats.baseStats.vitality + delta, mStats.baseStats.maxVitality); }

BaseStats Player::initialiseActorStats(const DiabloExe::CharacterStats& from)
{
BaseStats baseStats;
Expand Down
5 changes: 5 additions & 0 deletions apps/freeablo/faworld/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ namespace FAWorld

virtual void calculateStats(LiveActorStats& stats, const ActorStats& actorStats) const override;

void addStrength(int32_t delta);
void addMagic(int32_t delta);
void addDexterity(int32_t delta);
void addVitality(int32_t delta);

void moveToLevel(GameLevel* level, bool placeAtUpStairs);

// This isn't serialised as it must be set before saving can occur.
Expand Down
13 changes: 13 additions & 0 deletions apps/freeablo/faworld/playerbehaviour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
#include "fasavegame/gameloader.h"
#include "input/inputmanager.h"
#include "item/itembase.h"
#include "item/usableitem.h"
#include "player.h"
#include "potion.h"
#include "storedata.h"
#include <algorithm>
#include <engine/threadmanager.h>
Expand Down Expand Up @@ -206,6 +208,17 @@ namespace FAWorld

return;
}
case PlayerInput::Type::UseItem:
{
if (mPlayer->mInventory.getItemAt(input.mData.dataUseItem.target) &&
mPlayer->mInventory.getItemAt(input.mData.dataUseItem.target)->getAsUsableItem())
{
std::unique_ptr<Item> item = mPlayer->mInventory.remove(input.mData.dataUseItem.target);
item->getAsUsableItem()->applyEffect(*mPlayer);
}

return;
}
case PlayerInput::Type::PlayerJoined:
case PlayerInput::Type::PlayerLeft:
{
Expand Down
4 changes: 4 additions & 0 deletions apps/freeablo/faworld/playerinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ namespace FAWorld
shopkeeperId = loader.load<int32_t>();
}

void PlayerInput::UseItemData::save(Serial::Saver& saver) const { target.save(saver); }

void PlayerInput::UseItemData::load(Serial::Loader& loader) { target.load(loader); }

void PlayerInput::removeUnnecessaryInputs(std::vector<PlayerInput>& inputs)
{
// This should remove all but the last of each input type, per player.
Expand Down
9 changes: 8 additions & 1 deletion apps/freeablo/faworld/playerinput.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
MACRO(PlayerJoined) \
MACRO(PlayerLeft) \
MACRO(BuyItem) \
MACRO(SellItem)
MACRO(SellItem) \
MACRO(UseItem)

namespace Serial
{
Expand Down Expand Up @@ -156,6 +157,12 @@ namespace FAWorld
void save(Serial::Saver& saver) const;
void load(Serial::Loader& loader);
};
struct UseItemData
{
FAWorld::EquipTarget target;
void save(Serial::Saver& saver) const;
void load(Serial::Loader& loader);
};

// All this macro mess takes care of generating boilerplate code to wrap up the above structs into a union with a type enum, and
// save/load functions. So, eg, if mType == TargetTile, then you can access mData.dataTargetType. You can also call .save() and .load()
Expand Down
Loading

0 comments on commit 4ef76c1

Please sign in to comment.