Skip to content

Commit

Permalink
Merge branch 'feat/45/spells'
Browse files Browse the repository at this point in the history
  • Loading branch information
wheybags committed Feb 19, 2020
2 parents 74bfedc + 450da98 commit 72d6f2a
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 32 deletions.
88 changes: 85 additions & 3 deletions apps/freeablo/fagui/guimanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../faworld/equiptarget.h"
#include "../faworld/itemenums.h"
#include "../faworld/player.h"
#include "../faworld/spells.h"
#include "../faworld/world.h"
#include "dialogmanager.h"
#include "fa_nuklear.h"
Expand Down Expand Up @@ -397,7 +398,7 @@ namespace FAGui
31,
std::to_string(playerStats.getHp().current).c_str(),
playerStats.getHp().current < playerStats.getHp().max ? TextColor::red : TextColor::white);
fillTextField(ctx, 95, 321, 31, std::to_string(playerStats.getHp().max).c_str());
fillTextField(ctx, 95, 321, 31, std::to_string(playerStats.getMana().max).c_str());
fillTextField(ctx,
143,
321,
Expand All @@ -424,7 +425,88 @@ namespace FAGui

void GuiManager::spellsPanel(nk_context* ctx)
{
drawPanel(ctx, PanelType::spells, [&]() {});
drawPanel(ctx, PanelType::spells, [&]() {
nk_layout_space_begin(ctx, NK_STATIC, 0, INT_MAX);

FARender::Renderer* renderer = FARender::Renderer::get();
FARender::FASpriteGroup* selectedTabButtons = renderer->loadImage("data/spellbkb.cel");
FARender::FASpriteGroup* icons = renderer->loadImage("data/spelli2.cel");

int32_t buttonWidth = selectedTabButtons->getWidth();
int32_t buttonHeight = selectedTabButtons->getHeight();
int32_t iconWidth = icons->getWidth();
int32_t iconHeight = icons->getHeight();

nk_style_button buttonStyle = dummyStyle;

// Add the spell icons on the left of the panel
for (int i = 0; i < 7; i++)
{
auto spell = FAWorld::SpellData::spellbookLUT[mCurSpellbookTab][i];

auto spellData = FAWorld::SpellData(spell);
int frame = spellData.getFrameIndex();
int32_t yPos = 19 + i * 43;
nk_layout_space_push(ctx, nk_rect(10, yPos, iconHeight, iconWidth));

// Temporary quirk to only allow implemented spells to be used.
bool spellImplemented = false;
for (auto sp : FAWorld::SpellData::implementedSpells)
{
if (spell == sp)
{
spellImplemented = true;
break;
}
}
if (spellImplemented)
{
buttonStyle.normal = buttonStyle.hover = buttonStyle.active = nk_style_item_image(icons->getNkImage(frame));
if (nk_button_label_styled(ctx, &buttonStyle, "") && spellImplemented)
{
// Set active spell
FAWorld::PlayerInput::SetActiveSpellData input{spell};
Engine::EngineMain::get()->getLocalInputHandler()->addInput(FAWorld::PlayerInput(input, mPlayer->getId()));
}
}
else
{
// Grey out unimplemented spells.
nk_image_color(ctx, icons->getNkImage(frame), {64, 64, 64, 255});
}

// Highlight selected spell
if (spell == mPlayer->getActiveSpell())
nk_image(ctx, icons->getNkImage(42));

nk_layout_space_push(ctx, nk_rect(65, yPos + 3, 131, FARender::Renderer::get()->smallFont()->height));
smallText(ctx, spellData.name().c_str(), TextColor::white, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_TOP);

nk_layout_space_push(ctx, nk_rect(65, yPos + 14, 131, FARender::Renderer::get()->smallFont()->height));
smallText(ctx, "Skill", TextColor::white, NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_TOP);
}

// Add the buttons at the bottom of the panel
for (int i = 0; i < 4; i++)
{
int32_t xPos = 8 + i * 76;
nk_layout_space_push(ctx, nk_rect(xPos, 320, buttonWidth, buttonHeight));
buttonStyle.active = nk_style_item_image(selectedTabButtons->getNkImage(i));
if (mCurSpellbookTab == i)
buttonStyle.normal = buttonStyle.hover = buttonStyle.active;
else
buttonStyle.normal = buttonStyle.hover = nk_style_item_hide();
if (nk_button_label_styled(ctx, &buttonStyle, ""))
{
mCurSpellbookTab = i;
// As soon as button is released it returns to buttonStyle.hover (unselected), the next loop
// though here updates buttonStyle.hover to "selected", but there is a slight flicker between
// frames without the following:
nk_image(ctx, selectedTabButtons->getNkImage(i));
}
}
nk_layout_space_end(ctx);
});
}

void GuiManager::belt(nk_context* ctx)
Expand Down Expand Up @@ -587,7 +669,7 @@ namespace FAGui
// draw current hp into health bulb
drawBulb(stats.getHp().current, stats.getHp().max, healthBulbLeftOffset);
// and current mana
drawBulb(stats.getMana().current, stats.getMana().current, manaBulbLeftOffset);
drawBulb(stats.getMana().current, stats.getMana().max, manaBulbLeftOffset);

belt(ctx);
descriptionPanel(ctx, hoverStatus.getDescription(*Engine::EngineMain::get()->mWorld->getCurrentLevel()));
Expand Down
1 change: 1 addition & 0 deletions apps/freeablo/fagui/guimanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,6 @@ namespace FAGui
std::unique_ptr<MenuHandler> mMenuHandler;
const FAWorld::Item* mGoldSplitTarget = nullptr;
int mGoldSplitCnt = 0;
int mCurSpellbookTab = 0;
};
}
10 changes: 10 additions & 0 deletions apps/freeablo/faworld/actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "findpath.h"
#include "missile/missile.h"
#include "player.h"
#include "spells.h"
#include "world.h"
#include <diabloexe/diabloexe.h>
#include <diabloexe/monster.h>
Expand Down Expand Up @@ -344,6 +345,15 @@ namespace FAWorld
dealDamageToEnemy(enemy, meleeDamageVs(enemy));
}

bool Actor::castSpell(SpellId spell, Misc::Point targetPoint)
{
auto spellData = SpellData(spell);
Engine::ThreadManager::get()->playSound(spellData.soundEffect());
for (auto missileId : spellData.missiles())
activateMissile(missileId, targetPoint);
return true;
}

void Actor::activateMissile(MissileId id, Misc::Point targetPoint)
{
auto missile = std::make_unique<Missile::Missile>(id, *this, targetPoint);
Expand Down
2 changes: 2 additions & 0 deletions apps/freeablo/faworld/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "missile/missileenums.h"
#include "movementhandler.h"
#include "position.h"
#include "spellenums.h"
#include "target.h"
#include "world.h"
#include <misc/direction.h>
Expand Down Expand Up @@ -88,6 +89,7 @@ namespace FAWorld

virtual void calculateStats(LiveActorStats& stats, const ActorStats& actorStats) const;
const std::vector<std::unique_ptr<Missile::Missile>>& getMissiles() const { return mMissiles; }
virtual bool castSpell(SpellId spell, Misc::Point targetPoint);

protected:
void activateMissile(MissileId id, Misc::Point targetPoint);
Expand Down
2 changes: 2 additions & 0 deletions apps/freeablo/faworld/missile/missile.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ namespace FAWorld
switch (missileId)
{
case MissileId::firewall:
case MissileId::firewalla:
case MissileId::firewallc:
case MissileId::manashield:
return World::getTicksInPeriod("8"); // placeholder
default:
Expand Down
2 changes: 2 additions & 0 deletions apps/freeablo/faworld/missile/missileactorengagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace FAWorld
case MissileId::larrow:
return damageEnemyAndStop;
case MissileId::firewall:
case MissileId::firewalla:
case MissileId::firewallc:
return damageEnemy;
case MissileId::manashield: // TODO
default:
Expand Down
2 changes: 2 additions & 0 deletions apps/freeablo/faworld/missile/missilecreation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace FAWorld
case MissileId::larrow:
return animated16Direction;
case MissileId::firewall:
case MissileId::firewalla:
case MissileId::firewallc:
return firewall;
case MissileId::manashield:
return basicAnimated;
Expand Down
2 changes: 2 additions & 0 deletions apps/freeablo/faworld/missile/missilemovement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace FAWorld
case MissileId::larrow:
return linear;
case MissileId::firewall:
case MissileId::firewalla:
case MissileId::firewallc:
return fixed;
case MissileId::manashield:
return hoverOverCreator;
Expand Down
49 changes: 23 additions & 26 deletions apps/freeablo/faworld/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "itemmap.h"
#include "missile/missile.h"
#include "playerbehaviour.h"
#include "spells.h"
#include "world.h"
#include <fmt/format.h>
#include <misc/assert.h>
Expand Down Expand Up @@ -219,7 +220,7 @@ namespace FAWorld
Player::Player(World& world, FASaveGame::GameLoader& loader) : Actor(world, loader)
{
mPlayerClass = static_cast<PlayerClass>(loader.load<int32_t>());
mActiveMissileIndex = loader.load<uint32_t>();
mActiveSpell = (SpellId)loader.load<int32_t>();
initCommon();
mPlayerInitialised = true;
}
Expand All @@ -232,7 +233,7 @@ namespace FAWorld

Actor::save(saver);
saver.save(static_cast<int32_t>(mPlayerClass));
saver.save(mActiveMissileIndex);
saver.save((int32_t)mActiveSpell);
}

Player::~Player() { mWorld.deregisterPlayer(this); }
Expand Down Expand Up @@ -496,34 +497,30 @@ namespace FAWorld
stats = ActorStats(*stats.mActor, baseStats, from.mNextLevelExp);
}

static const std::vector<MissileId> mImplementedMissiles = {
MissileId::arrow, MissileId::firebolt, MissileId::firewall, MissileId::manashield, MissileId::farrow, MissileId::larrow};
bool Player::castSpell(SpellId spell, Misc::Point targetPoint)
{
auto spellData = SpellData(spell);
auto& mana = mStats.getMana();
auto manaCost = spellData.manaCost();

// Note: These checks have temporarily been removed for easier testing/development
// if (!getLevel() || (getLevel()->isTown() && !spellData.canCastInTown()) || mana.current < manaCost)
// return false;

if (Actor::castSpell(spell, targetPoint))
{
mana.add(-manaCost);
return true;
}
return false;
}

void Player::setActiveSpellNumber(int32_t spellNumber)
{
// TODO: This is coming from Hotkeys (F5 -> F8).
// This is probably the wrong place to be handling this input.
(void)spellNumber;
// Hack for testing, loop through implemented missiles.
mActiveMissileIndex++;
if (mActiveMissileIndex >= mImplementedMissiles.size())
mActiveMissileIndex = 0;
}

void Player::castActiveSpell(Misc::Point targetPoint)
{
// Hack for testing, loop through implemented missiles.
auto missileId = mImplementedMissiles[mActiveMissileIndex];
switch (missileId)
{
case MissileId::arrow:
case MissileId::farrow:
case MissileId::larrow:
// Arrow sounds will need to be implemented like Actor::doMeleeHit().
Engine::ThreadManager::get()->playSound("sfx/misc/bfire.wav");
break;
default:
// Spell sounds will come from DiabloExe::getSpellsDataTable()[spellId].mSoundEffect.
break;
}
activateMissile(missileId, targetPoint);
}
void Player::castActiveSpell(Misc::Point targetPoint) { castSpell(mActiveSpell, targetPoint); }
}
5 changes: 4 additions & 1 deletion apps/freeablo/faworld/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ namespace FAWorld
PlayerClass getClass() const { return mPlayerClass; }
virtual bool canCriticalHit() const override { return mPlayerClass == PlayerClass::warrior; }

bool castSpell(SpellId spell, Misc::Point targetPoint) override;
void setActiveSpellNumber(int32_t spellNumber);
SpellId getActiveSpell() const { return mActiveSpell; }
void setActiveSpell(SpellId spell) { mActiveSpell = spell; }
void castActiveSpell(Misc::Point targetPoint);

virtual void calculateStats(LiveActorStats& stats, const ActorStats& actorStats) const override;
Expand Down Expand Up @@ -71,6 +74,6 @@ namespace FAWorld

int32_t mInventoryChangedCallCount = 0; // not serialised, only used to determine if inventory changed since we last calculated stats
PlayerClass mPlayerClass = PlayerClass::warrior;
uint32_t mActiveMissileIndex = 0; // Temporary for testing missiles.
SpellId mActiveSpell = SpellId::firebolt;
};
}
5 changes: 5 additions & 0 deletions apps/freeablo/faworld/playerbehaviour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ namespace FAWorld
mPlayer->getWorld()->getItemFactory());
return;
}
case PlayerInput::Type::SetActiveSpell:
{
mPlayer->setActiveSpell(input.mData.dataSetActiveSpell.spell);
return;
}
case PlayerInput::Type::BuyItem:
{
auto& items = mPlayer->getWorld()->getStoreData().griswoldBasicItems;
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 @@ -126,6 +126,10 @@ namespace FAWorld

void PlayerInput::InventorySlotClickedData::load(Serial::Loader& loader) { slot.load(loader); }

void PlayerInput::SetActiveSpellData::save(Serial::Saver& saver) const { saver.save((int32_t)spell); }

void PlayerInput::SetActiveSpellData::load(Serial::Loader& loader) { spell = (SpellId)loader.load<int32_t>(); }

void PlayerInput::SplitGoldStackIntoCursorData::save(Serial::Saver& saver) const
{
saver.save(invX);
Expand Down
9 changes: 9 additions & 0 deletions apps/freeablo/faworld/playerinput.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include "../faworld/equiptarget.h"
#include "../faworld/spellenums.h"
#include "target.h"
#include <cstdint>
#include <misc/direction.h>
Expand All @@ -14,6 +15,7 @@
MACRO(PrepareSpell) \
MACRO(ChangeLevel) \
MACRO(InventorySlotClicked) \
MACRO(SetActiveSpell) \
MACRO(SplitGoldStackIntoCursor) \
MACRO(PlayerJoined) \
MACRO(PlayerLeft) \
Expand Down Expand Up @@ -101,6 +103,13 @@ namespace FAWorld
void save(Serial::Saver& saver) const;
void load(Serial::Loader& loader);
};
struct SetActiveSpellData
{
SpellId spell;

void save(Serial::Saver& saver) const;
void load(Serial::Loader& loader);
};
struct SplitGoldStackIntoCursorData
{
int32_t invX, invY;
Expand Down
46 changes: 46 additions & 0 deletions apps/freeablo/faworld/spellenums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

namespace FAWorld
{
enum class SpellId
{
null = 0x0,
firebolt = 0x1,
heal = 0x2,
lightning = 0x3,
flash = 0x4,
identify = 0x5,
firewall = 0x6,
town = 0x7,
stone = 0x8,
infra = 0x9,
rndteleport = 0xa,
manashield = 0xb,
fireball = 0xc,
guardian = 0xd,
chain = 0xe,
wave = 0xf,
doomserp = 0x10,
blodrit = 0x11,
nova = 0x12,
invisibil = 0x13,
flame = 0x14,
golem = 0x15,
blodboil = 0x16,
teleport = 0x17,
apoca = 0x18,
etherealize = 0x19,
repair = 0x1a,
recharge = 0x1b,
disarm = 0x1c,
element = 0x1d,
cbolt = 0x1e,
hbolt = 0x1f,
resurrect = 0x20,
telekinesis = 0x21,
healother = 0x22,
flare = 0x23,
bonespirit = 0x24,
invalid = -1
};
}
Loading

0 comments on commit 72d6f2a

Please sign in to comment.