Skip to content

Commit

Permalink
load starting loadout dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
ephphatha committed Sep 17, 2023
1 parent 00aa5ee commit 3d4e863
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 55 deletions.
58 changes: 29 additions & 29 deletions Source/items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3003,40 +3003,40 @@ void CreatePlrItems(Player &player)
item.clear();
}

switch (player._pClass) {
case HeroClass::Warrior:
for (_item_indexes itemData : { IDI_WARRIOR, IDI_WARRSHLD, IDI_WARRCLUB, IDI_HEAL, IDI_HEAL })
CreateStartingItem(player, itemData);
break;
case HeroClass::Rogue:
for (_item_indexes itemData : { IDI_ROGUE, IDI_HEAL, IDI_HEAL })
CreateStartingItem(player, itemData);
break;
case HeroClass::Sorcerer:
for (_item_indexes itemData : { gbIsHellfire ? IDI_SORCERER : IDI_SORCERER_DIABLO, gbIsHellfire ? IDI_HEAL : IDI_MANA, gbIsHellfire ? IDI_HEAL : IDI_MANA })
CreateStartingItem(player, itemData);
break;
case HeroClass::Monk:
for (_item_indexes itemData : { IDI_SHORTSTAFF, IDI_HEAL, IDI_HEAL })
CreateStartingItem(player, itemData);
break;
case HeroClass::Bard:
for (_item_indexes itemData : { IDI_BARDSWORD, IDI_BARDDAGGER, IDI_HEAL, IDI_HEAL })
CreateStartingItem(player, itemData);
break;
case HeroClass::Barbarian:
for (_item_indexes itemData : { IDI_BARBARIAN, IDI_WARRSHLD, IDI_HEAL, IDI_HEAL })
const PlayerStartingLoadoutData &loadout = GetPlayerStartingLoadoutForClass(player._pClass);

if (loadout.spell != SpellID::Null && loadout.spellLevel > 0) {
player._pMemSpells = GetSpellBitmask(loadout.spell);
player._pRSplType = SpellType::Spell;
player._pRSpell = loadout.spell;
player._pSplLvl[static_cast<unsigned>(loadout.spell)] = loadout.spellLevel;
} else {
player._pMemSpells = 0;
}

if (loadout.skill != SpellID::Null) {
player._pAblSpells = GetSpellBitmask(loadout.skill);
if (player._pRSplType == SpellType::Invalid) {
player._pRSplType = SpellType::Skill;
player._pRSpell = loadout.skill;
}
}

for (auto &itemChoice : loadout.items) {
_item_indexes itemData = gbIsHellfire && itemChoice.hellfire != _item_indexes::IDI_NONE ? itemChoice.hellfire : itemChoice.diablo;
if (itemData != _item_indexes::IDI_NONE)
CreateStartingItem(player, itemData);
break;
}

Item &goldItem = player.InvList[player._pNumInv];
MakeGoldStack(goldItem, 100);
if (loadout.gold > 0) {
Item &goldItem = player.InvList[player._pNumInv];
MakeGoldStack(goldItem, loadout.gold);

player._pNumInv++;
player.InvGrid[30] = player._pNumInv;
player._pNumInv++;
player.InvGrid[30] = player._pNumInv;

player._pGold = goldItem._ivalue;
player._pGold = goldItem._ivalue;
}

CalcPlrItemVals(player, false);
}
Expand Down
21 changes: 2 additions & 19 deletions Source/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2310,28 +2310,12 @@ void CreatePlayer(Player &player, HeroClass c)
player._pLightRad = 10;
player._pInfraFlag = false;

player._pRSplType = SpellType::Skill;
SpellID s = player.getPlayerData().skill;
player._pAblSpells = GetSpellBitmask(s);
player._pRSpell = s;

if (c == HeroClass::Sorcerer) {
player._pMemSpells = GetSpellBitmask(SpellID::Firebolt);
player._pRSplType = SpellType::Spell;
player._pRSpell = SpellID::Firebolt;
} else {
player._pMemSpells = 0;
}

for (uint8_t &spellLevel : player._pSplLvl) {
spellLevel = 0;
}

player._pSpellFlags = SpellFlag::None;

if (player._pClass == HeroClass::Sorcerer) {
player._pSplLvl[static_cast<int8_t>(SpellID::Firebolt)] = 2;
}
player._pRSplType = SpellType::Invalid;

// Initializing the hotkey bindings to no selection
std::fill(player._pSplHotKey, player._pSplHotKey + NumHotkeys, SpellID::Invalid);
Expand Down Expand Up @@ -2517,8 +2501,7 @@ void InitPlayer(Player &player, bool firstTime)
ActivateVision(player.position.tile, player._pLightRad, player.getId());
}

SpellID s = player.getPlayerData().skill;
player._pAblSpells = GetSpellBitmask(s);
player._pAblSpells = GetSpellBitmask(GetPlayerStartingLoadoutForClass(player._pClass).skill);

player._pInvincible = false;

Expand Down
31 changes: 24 additions & 7 deletions Source/playerdat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,30 @@ void LoadClassesAttributes()
/** Contains the data related to each player class. */
const PlayerData PlayersData[] = {
// clang-format off
// HeroClass className, skill
// HeroClass className
// TRANSLATORS: Player Block start
/* HeroClass::Warrior */ { N_("Warrior"), SpellID::ItemRepair },
/* HeroClass::Rogue */ { N_("Rogue"), SpellID::TrapDisarm },
/* HeroClass::Sorcerer */ { N_("Sorcerer"), SpellID::StaffRecharge },
/* HeroClass::Monk */ { N_("Monk"), SpellID::Search },
/* HeroClass::Bard */ { N_("Bard"), SpellID::Identify },
/* HeroClass::Warrior */ { N_("Warrior"), },
/* HeroClass::Rogue */ { N_("Rogue"), },
/* HeroClass::Sorcerer */ { N_("Sorcerer"), },
/* HeroClass::Monk */ { N_("Monk"), },
/* HeroClass::Bard */ { N_("Bard"), },
// TRANSLATORS: Player Block end
/* HeroClass::Barbarian */ { N_("Barbarian"), SpellID::Rage },
/* HeroClass::Barbarian */ { N_("Barbarian"), },
// clang-format on
};

const std::array<PlayerStartingLoadoutData, enum_size<HeroClass>::value> PlayersStartingLoadoutData { {
// clang-format off
// HeroClass skill, spell, spellLevel, items[0].diablo, items[0].hellfire, items[1].diablo, items[1].hellfire, items[2].diablo, items[2].hellfire, items[3].diablo, items[3].hellfire, items[4].diablo, items[4].hellfire, gold,
/* HeroClass::Warrior */ { SpellID::ItemRepair, SpellID::Null, 0, { { { IDI_WARRIOR, IDI_WARRIOR, }, { IDI_WARRSHLD, IDI_WARRSHLD, }, { IDI_WARRCLUB, IDI_WARRCLUB, }, { IDI_HEAL, IDI_HEAL, }, { IDI_HEAL, IDI_HEAL, }, }, }, 100, },
/* HeroClass::Rogue */ { SpellID::TrapDisarm, SpellID::Null, 0, { { { IDI_ROGUE, IDI_ROGUE, }, { IDI_HEAL, IDI_HEAL, }, { IDI_HEAL, IDI_HEAL, }, { IDI_NONE, IDI_NONE, }, { IDI_NONE, IDI_NONE, }, }, }, 100, },
/* HeroClass::Sorcerer */ { SpellID::StaffRecharge, SpellID::Fireball, 2, { { { IDI_SORCERER_DIABLO, IDI_SORCERER, }, { IDI_MANA, IDI_HEAL, }, { IDI_MANA, IDI_HEAL, }, { IDI_NONE, IDI_NONE, }, { IDI_NONE, IDI_NONE, }, }, }, 100, },
/* HeroClass::Monk */ { SpellID::Search, SpellID::Null, 0, { { { IDI_SHORTSTAFF, IDI_SHORTSTAFF, }, { IDI_HEAL, IDI_HEAL, }, { IDI_HEAL, IDI_HEAL, }, { IDI_NONE, IDI_NONE, }, { IDI_NONE, IDI_NONE, }, }, }, 100, },
/* HeroClass::Bard */ { SpellID::Identify, SpellID::Null, 0, { { { IDI_BARDSWORD, IDI_BARDSWORD, }, { IDI_BARDDAGGER, IDI_BARDDAGGER, }, { IDI_HEAL, IDI_HEAL, }, { IDI_HEAL, IDI_HEAL, }, { IDI_NONE, IDI_NONE, }, }, }, 100, },
/* HeroClass::Barbarian */ { SpellID::Rage, SpellID::Null, 0, { { { IDI_BARBARIAN, IDI_BARBARIAN, }, { IDI_WARRSHLD, IDI_WARRSHLD, }, { IDI_HEAL, IDI_HEAL, }, { IDI_HEAL, IDI_HEAL, }, { IDI_NONE, IDI_NONE, }, }, }, 100, }
// clang-format on
} };

} // namespace

const ClassAttributes &GetClassAttributes(HeroClass playerClass)
Expand Down Expand Up @@ -301,6 +313,11 @@ const PlayerCombatData &GetPlayerCombatDataForClass(HeroClass clazz)
return PlayersCombatData[static_cast<size_t>(clazz)];
}

const PlayerStartingLoadoutData &GetPlayerStartingLoadoutForClass(HeroClass clazz)
{
return PlayersStartingLoadoutData[static_cast<size_t>(clazz)];
}

/** Contains the data related to each player class. */
const PlayerSpriteData PlayersSpriteData[] = {
// clang-format off
Expand Down
31 changes: 31 additions & 0 deletions Source/playerdat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <cstdint>

#include "effects.h"
#include "itemdat.h"
#include "spelldat.h"

namespace devilution {
Expand Down Expand Up @@ -78,6 +79,35 @@ struct PlayerCombatData {
uint8_t baseMagicToHit;
};

/**
* @brief Data used to set known skills and provide initial equipment when starting a new game
*
* Items will be created in order starting with item 1, 2, etc. If the item can be equipped it
* will be placed in the first available slot, otherwise if it fits on the belt it will be
* placed in the first free space, finally being placed in the first free inventory position.
*
* The active game mode at the time we're creating a new character controls the choice of item
* type. ItemType.hellfire is used if we're in Hellfire mode, ItemType.diablo otherwise.
*/
struct PlayerStartingLoadoutData {
/* Class Skill */
SpellID skill;
/* Starting Spell (if any) */
SpellID spell;
/* Initial level of the starting spell */
uint8_t spellLevel;

struct ItemType {
_item_indexes diablo;
_item_indexes hellfire;
};

std::array<ItemType, 5> items;

/* Initial gold amount, up to a single stack (5000 gold) */
uint16_t gold;
};

struct PlayerSpriteData {
/* Class Directory Path */
const char *classPath;
Expand Down Expand Up @@ -170,6 +200,7 @@ uint32_t GetNextExperienceThresholdForLevel(unsigned level);
uint8_t GetMaximumCharacterLevel();
const PlayerData &GetPlayerDataForClass(HeroClass clazz);
const PlayerCombatData &GetPlayerCombatDataForClass(HeroClass clazz);
const PlayerStartingLoadoutData &GetPlayerStartingLoadoutForClass(HeroClass clazz);
extern const PlayerSpriteData PlayersSpriteData[];
extern const PlayerAnimData PlayersAnimData[];

Expand Down

0 comments on commit 3d4e863

Please sign in to comment.