Browse Source

Clean up player graphic loading

pull/5112/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
b21ebffaf2
  1. 2
      Source/loadsave.cpp
  2. 219
      Source/player.cpp
  3. 4
      Source/player.h

2
Source/loadsave.cpp

@ -1120,7 +1120,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(player.AnimInfo.numberOfFrames);
file.WriteLE<int32_t>(player.AnimInfo.currentFrame + 1);
// write _pAnimWidth for vanilla compatibility
int animWidth = player.AnimInfo.celSprite ? player.AnimInfo.celSprite->Width() : 96;
const int animWidth = player.getSpriteWidth();
file.WriteLE<int32_t>(animWidth);
// write _pAnimWidth2 for vanilla compatibility
file.WriteLE<int32_t>(CalculateWidth2(animWidth));

219
Source/player.cpp

@ -1771,6 +1771,67 @@ void CheckCheatStats(Player &player)
}
}
HeroClass GetPlayerSpriteClass(HeroClass cls)
{
if (cls == HeroClass::Bard && !hfbard_mpq)
return HeroClass::Rogue;
if (cls == HeroClass::Barbarian && !hfbarb_mpq)
return HeroClass::Warrior;
return cls;
}
PlayerWeaponGraphic GetPlayerWeaponGraphic(player_graphic graphic, PlayerWeaponGraphic weaponGraphic)
{
if (leveltype == DTYPE_TOWN && IsAnyOf(graphic, player_graphic::Lightning, player_graphic::Fire, player_graphic::Magic)) {
// If the hero doesn't hold the weapon in town then we should use the unarmed animation for casting
switch (weaponGraphic) {
case PlayerWeaponGraphic::Mace:
case PlayerWeaponGraphic::Sword:
return PlayerWeaponGraphic::Unarmed;
case PlayerWeaponGraphic::SwordShield:
case PlayerWeaponGraphic::MaceShield:
return PlayerWeaponGraphic::UnarmedShield;
default:
break;
}
}
return weaponGraphic;
}
uint16_t GetPlayerSpriteWidth(HeroClass cls, player_graphic graphic, PlayerWeaponGraphic weaponGraphic)
{
switch (graphic) {
case player_graphic::Stand:
case player_graphic::Walk:
if (cls == HeroClass::Monk)
return 112;
break;
case player_graphic::Attack:
if (cls == HeroClass::Monk)
return 130;
else if (weaponGraphic != PlayerWeaponGraphic::Bow || !(cls == HeroClass::Warrior || cls == HeroClass::Barbarian))
return 128;
break;
case player_graphic::Hit:
case player_graphic::Block:
if (cls == HeroClass::Monk)
return 98;
break;
case player_graphic::Lightning:
case player_graphic::Fire:
case player_graphic::Magic:
if (cls == HeroClass::Monk)
return 114;
else if (cls == HeroClass::Sorcerer)
return 128;
break;
case player_graphic::Death:
return (cls == HeroClass::Monk) ? 160 : 128;
break;
}
return 96;
}
} // namespace
void Player::CalcScrolls()
@ -1978,6 +2039,54 @@ void Player::ReadySpellFromEquipment(inv_body_loc bodyLocation)
}
}
player_graphic Player::getGraphic() const
{
switch (_pmode) {
case PM_STAND:
case PM_NEWLVL:
case PM_QUIT:
return player_graphic::Stand;
case PM_WALK_NORTHWARDS:
case PM_WALK_SOUTHWARDS:
case PM_WALK_SIDEWAYS:
return player_graphic::Walk;
case PM_ATTACK:
case PM_RATTACK:
return player_graphic::Attack;
case PM_BLOCK:
return player_graphic::Block;
case PM_SPELL:
// We don't have the spell data for other players.
if (this == MyPlayer) {
switch (spelldata[_pSpell].sType) {
case STYPE_FIRE:
return player_graphic::Fire;
case STYPE_LIGHTNING:
return player_graphic::Lightning;
case STYPE_MAGIC:
return player_graphic::Magic;
}
}
return player_graphic::Fire;
case PM_GOTHIT:
return player_graphic::Hit;
case PM_DEATH:
return player_graphic::Death;
default:
app_fatal("SyncPlrAnim");
}
}
uint16_t Player::getSpriteWidth() const
{
if (!HeadlessMode)
return AnimInfo.celSprite->Width();
const player_graphic graphic = getGraphic();
const HeroClass cls = GetPlayerSpriteClass(_pClass);
const PlayerWeaponGraphic weaponGraphic = GetPlayerWeaponGraphic(graphic, static_cast<PlayerWeaponGraphic>(_pgfxnum & 0xF));
return GetPlayerSpriteWidth(cls, graphic, weaponGraphic);
}
void Player::UpdatePreviewCelSprite(_cmd_id cmdId, Point point, uint16_t wParam1, uint16_t wParam2)
{
// if game is not running don't show a preview
@ -2142,18 +2251,10 @@ void LoadPlrGFX(Player &player, player_graphic graphic)
if (animationData.RawData != nullptr)
return;
HeroClass c = player._pClass;
if (c == HeroClass::Bard && !hfbard_mpq) {
c = HeroClass::Rogue;
} else if (c == HeroClass::Barbarian && !hfbarb_mpq) {
c = HeroClass::Warrior;
}
auto animWeaponId = static_cast<PlayerWeaponGraphic>(player._pgfxnum & 0xF);
int animationWidth = 96;
bool useUnarmedAnimationInTown = false;
const HeroClass cls = GetPlayerSpriteClass(player._pClass);
const PlayerWeaponGraphic animWeaponId = GetPlayerWeaponGraphic(graphic, static_cast<PlayerWeaponGraphic>(player._pgfxnum & 0xF));
const char *cs = ClassPathTbl[static_cast<std::size_t>(c)];
const char *path = ClassPathTbl[static_cast<std::size_t>(cls)];
const char *szCel;
switch (graphic) {
@ -2161,61 +2262,35 @@ void LoadPlrGFX(Player &player, player_graphic graphic)
szCel = "AS";
if (leveltype == DTYPE_TOWN)
szCel = "ST";
if (c == HeroClass::Monk)
animationWidth = 112;
break;
case player_graphic::Walk:
szCel = "AW";
if (leveltype == DTYPE_TOWN)
szCel = "WL";
if (c == HeroClass::Monk)
animationWidth = 112;
break;
case player_graphic::Attack:
if (leveltype == DTYPE_TOWN)
return;
szCel = "AT";
if (c == HeroClass::Monk)
animationWidth = 130;
else if (animWeaponId != PlayerWeaponGraphic::Bow || !(c == HeroClass::Warrior || c == HeroClass::Barbarian))
animationWidth = 128;
break;
case player_graphic::Hit:
if (leveltype == DTYPE_TOWN)
return;
szCel = "HT";
if (c == HeroClass::Monk)
animationWidth = 98;
break;
case player_graphic::Lightning:
szCel = "LM";
useUnarmedAnimationInTown = true;
if (c == HeroClass::Monk)
animationWidth = 114;
else if (c == HeroClass::Sorcerer)
animationWidth = 128;
break;
case player_graphic::Fire:
szCel = "FM";
useUnarmedAnimationInTown = true;
if (c == HeroClass::Monk)
animationWidth = 114;
else if (c == HeroClass::Sorcerer)
animationWidth = 128;
break;
case player_graphic::Magic:
szCel = "QM";
useUnarmedAnimationInTown = true;
if (c == HeroClass::Monk)
animationWidth = 114;
else if (c == HeroClass::Sorcerer)
animationWidth = 128;
break;
case player_graphic::Death:
if (animWeaponId != PlayerWeaponGraphic::Unarmed)
return;
szCel = "DT";
animationWidth = (c == HeroClass::Monk) ? 160 : 128;
break;
case player_graphic::Block:
if (leveltype == DTYPE_TOWN)
@ -2223,32 +2298,18 @@ void LoadPlrGFX(Player &player, player_graphic graphic)
if (!player._pBlockFlag)
return;
szCel = "BL";
if (c == HeroClass::Monk)
animationWidth = 98;
break;
default:
app_fatal("PLR:2");
}
if (leveltype == DTYPE_TOWN && useUnarmedAnimationInTown) {
// If the hero doesn't hold the weapon in town then we should use the unarmed animation for casting
switch (animWeaponId) {
case PlayerWeaponGraphic::Mace:
case PlayerWeaponGraphic::Sword:
animWeaponId = PlayerWeaponGraphic::Unarmed;
break;
case PlayerWeaponGraphic::SwordShield:
case PlayerWeaponGraphic::MaceShield:
animWeaponId = PlayerWeaponGraphic::UnarmedShield;
break;
default:
break;
}
}
if (HeadlessMode)
return;
char prefix[3] = { CharChar[static_cast<std::size_t>(c)], ArmourChar[player._pgfxnum >> 4], WepChar[static_cast<std::size_t>(animWeaponId)] };
char prefix[3] = { CharChar[static_cast<std::size_t>(cls)], ArmourChar[player._pgfxnum >> 4], WepChar[static_cast<std::size_t>(animWeaponId)] };
char pszName[256];
*fmt::format_to(pszName, FMT_COMPILE(R"(PlrGFX\{0}\{1}\{1}{2}.CL2)"), cs, string_view(prefix, 3), szCel) = 0;
*fmt::format_to(pszName, FMT_COMPILE(R"(PlrGFX\{0}\{1}\{1}{2}.CL2)"), path, string_view(prefix, 3), szCel) = 0;
const uint16_t animationWidth = GetPlayerSpriteWidth(cls, graphic, animWeaponId);
SetPlayerGPtrs(pszName, animationData.RawData, animationData.CelSpritesForDirections, animationWidth);
}
@ -3440,51 +3501,7 @@ void CheckPlrSpell(bool isShiftHeld, spell_id spellID, spell_type spellType)
void SyncPlrAnim(Player &player)
{
player_graphic graphic;
switch (player._pmode) {
case PM_STAND:
case PM_NEWLVL:
case PM_QUIT:
graphic = player_graphic::Stand;
break;
case PM_WALK_NORTHWARDS:
case PM_WALK_SOUTHWARDS:
case PM_WALK_SIDEWAYS:
graphic = player_graphic::Walk;
break;
case PM_ATTACK:
case PM_RATTACK:
graphic = player_graphic::Attack;
break;
case PM_BLOCK:
graphic = player_graphic::Block;
break;
case PM_SPELL:
graphic = player_graphic::Fire;
if (&player == MyPlayer) {
switch (spelldata[player._pSpell].sType) {
case STYPE_FIRE:
graphic = player_graphic::Fire;
break;
case STYPE_LIGHTNING:
graphic = player_graphic::Lightning;
break;
case STYPE_MAGIC:
graphic = player_graphic::Magic;
break;
}
}
break;
case PM_GOTHIT:
graphic = player_graphic::Hit;
break;
case PM_DEATH:
graphic = player_graphic::Death;
break;
default:
app_fatal("SyncPlrAnim");
}
const player_graphic graphic = player.getGraphic();
player.AnimInfo.celSprite = player.AnimationData[static_cast<size_t>(graphic)].GetCelSpritesForDirection(player._pdir);
// Ensure ScrollInfo is initialized correctly
ScrollViewPort(player, WalkSettings[static_cast<size_t>(player._pdir)].scrollDir);

4
Source/player.h

@ -698,6 +698,10 @@ struct Player {
return false;
}
[[nodiscard]] player_graphic getGraphic() const;
[[nodiscard]] uint16_t getSpriteWidth() const;
/**
* @brief Updates previewCelSprite according to new requested command
* @param cmdId What command is requested

Loading…
Cancel
Save