Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions HeavenClient/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ add_executable(HeavenClient
IO/UITypes/UITeleportRock.h
IO/UITypes/UIMegaphone.cpp
IO/UITypes/UIMegaphone.h
IO/UITypes/UIPetChooser.cpp
IO/UITypes/UIPetChooser.h
IO/UITypes/UIItemMegaphone.cpp
IO/UITypes/UIItemMegaphone.h
IO/UITypes/UIInviteCard.cpp
Expand Down
6 changes: 5 additions & 1 deletion HeavenClient/Character/Char.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,15 @@ namespace ms
}
}

for (auto &pet : pets)
for (size_t i = 0; i < pets.size(); i++)
{
PetLook &pet = pets[i];

if (!pet.get_itemid())
continue;

pet.set_wear(look.get_pet_wear(i));

// Another's pet goes where its owner's client says.
if (pet.is_local())
{
Expand Down
24 changes: 24 additions & 0 deletions HeavenClient/Character/Look/CharLook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "AttackStances.h"

#include "../Pets.h"

#include "../../Data/WeaponData.h"

namespace ms
Expand All @@ -32,7 +34,18 @@ namespace ms
set_face(entry.faceid);

for (auto &equip : entry.equips)
{
// Pet equipment is the pets', not the character's.
if (pets::is_equip_part(equip.first))
{
if (int8_t index = pets::wear_owner(equip.first); index >= 0)
pet_wear[index] = equip.second;

continue;
}

add_equip(equip.second);
}
}

CharLook::CharLook()
Expand Down Expand Up @@ -658,6 +671,17 @@ namespace ms
return face;
}

int32_t CharLook::get_pet_wear(size_t index) const
{
return index < pet_wear.size() ? pet_wear[index] : 0;
}

void CharLook::set_pet_wear(size_t index, int32_t itemid)
{
if (index < pet_wear.size())
pet_wear[index] = itemid;
}

const CharEquips &CharLook::get_equips() const
{
return equips;
Expand Down
8 changes: 8 additions & 0 deletions HeavenClient/Character/Look/CharLook.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//////////////////////////////////////////////////////////////////////////////////
#pragma once

#include <array>
#include <string>

#include <cstddef>
Expand Down Expand Up @@ -59,6 +60,12 @@ namespace ms
void add_equip(int32_t equipid);
void remove_equip(EquipSlot::Id slot);

// The clothes the pet at `index` in the list wears (body parts 14,
// 30 and 38), 0 for none.
int32_t get_pet_wear(size_t index) const;

void set_pet_wear(size_t index, int32_t itemid);

void attack(bool degenerate);

// Change to a regular attack stance from get_attackstance.
Expand Down Expand Up @@ -154,6 +161,7 @@ namespace ms
const Hair *hair;
const Face *face;
CharEquips equips;
std::array<int32_t, 3> pet_wear = {};

Randomizer randomizer;
TimedBool alerted;
Expand Down
101 changes: 89 additions & 12 deletions HeavenClient/Character/Look/PetLook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "../../Constants.h"
#include "../../Audio/Audio.h"
#include "../../Data/PetData.h"
#include "../../Util/Misc.h"
#include "../../Util/Randomizer.h"

#include <nlnx/nx.hpp>
Expand All @@ -41,6 +42,40 @@ namespace ms

return { type, pets::action(reaction.act, customs), text };
}

// The animations of the stances, as Item.nx Pet/<id>.img names them.
const char *STANCE_NAMES[PetLook::Stance::LENGTH] = {
"move", "stand0", "jump", "alert", "prone", "fly", "hang", ""
};

// The frames of `src`, by their number.
std::vector<Texture> frames(nl::node src)
{
std::vector<Texture> textures;

for (nl::node sub : src)
{
if (sub.data_type() != nl::node::type::bitmap)
continue;

int16_t index = string_conversion::or_default<int16_t>(sub.name(), -1);

if (index < 0 || index >= 64)
continue;

if (static_cast<size_t>(index) >= textures.size())
textures.resize(index + 1);

textures[index] = sub;
}

return textures;
}

nl::node clothes(int32_t wear, int32_t itemid)
{
return nl::nx::character["PetEquip"]["0" + std::to_string(wear) + ".img"][std::to_string(itemid)];
}
}

PetLook::Stance PetLook::stancebyvalue(uint8_t value)
Expand All @@ -66,7 +101,7 @@ namespace ms
shown({ static_cast<double>(entry.position.x()),
static_cast<double>(entry.position.y()), 0.0, 0.0,
entry.fh, entry.stance }),
action(-1), effecting(false), pending(false), still(0)
action(-1), wear(0), effecting(false), pending(false), still(0)
{
set_position(entry.position.x(), entry.position.y());
set_stance(entry.stance);
Expand All @@ -78,32 +113,33 @@ namespace ms
std::string strid = std::to_string(itemid);
nl::node src = nl::nx::item["Pet"][strid + ".img"];

animations[Stance::MOVE] = src["move"];
animations[Stance::STAND] = src["stand0"];
animations[Stance::JUMP] = src["jump"];
animations[Stance::ALERT] = src["alert"];
animations[Stance::PRONE] = src["prone"];
animations[Stance::FLY] = src["fly"];
animations[Stance::HANG] = src["hang"];
for (size_t i = 0; i < Stance::WARP; i++)
animations[static_cast<Stance>(i)] = src[STANCE_NAMES[i]];

nl::node effsrc = nl::nx::effect["PetEff.img"][strid];

animations[Stance::WARP] = effsrc["warp"];
}

PetLook::PetLook() : itemid(0), serial(0), local(false), stance(Stance::STAND), flip(false),
shown({ 0.0, 0.0, 0.0, 0.0, 0, 0 }), action(-1), effecting(false), pending(false),
shown({ 0.0, 0.0, 0.0, 0.0, 0, 0 }), action(-1), wear(0), effecting(false), pending(false),
still(0)
{}

void PetLook::draw(double viewx, double viewy, float alpha) const
{
Point<int16_t> absp = phobj.get_absolute(viewx, viewy, alpha);
DrawArgument args = DrawArgument(absp, flip);

if (action >= 0)
acting.draw(DrawArgument(absp, flip), alpha);
else
animations[stance].draw(DrawArgument(absp, flip), alpha);
{
acting.draw(args, alpha);
draw_dressing(acting_dressing, acting, args, alpha);
} else
{
animations[stance].draw(args, alpha);
draw_dressing(dressing[stance], animations[stance], args, alpha);
}

if (effecting)
effect.draw(DrawArgument(absp), alpha);
Expand Down Expand Up @@ -288,6 +324,8 @@ namespace ms
{
acting = src;
action = said.action;
acting_name = actname;
acting_dressing = wear ? frames(clothes(wear, itemid)[actname]) : std::vector<Texture>();
}

// A command's answer plays the pet's sound for its own actions.
Expand Down Expand Up @@ -450,12 +488,51 @@ namespace ms
return serial;
}

Point<int16_t> PetLook::get_position() const
{
return phobj.get_position();
}

bool PetLook::is_on_ground() const
{
return phobj.onground;
}

const PhysicsObject &PetLook::get_phobj() const
{
return phobj;
}

void PetLook::set_name(const std::string &n)
{
name = n;
namelabel.change_text(name);
}

void PetLook::set_wear(int32_t w)
{
if (wear == w)
return;

wear = w;

nl::node src = wear ? clothes(wear, itemid) : nl::node();

for (size_t i = 0; i < Stance::WARP; i++)
dressing[static_cast<Stance>(i)] = frames(src[STANCE_NAMES[i]]);

acting_dressing = action >= 0 ? frames(src[acting_name]) : std::vector<Texture>();
}

void PetLook::draw_dressing(const std::vector<Texture> &textures, const Animation &animation,
const DrawArgument &args, float alpha) const
{
size_t index = animation.get_frame_index(alpha);

if (index < textures.size())
textures[index].draw(args);
}

bool PetLook::is_local() const
{
return local;
Expand Down
21 changes: 21 additions & 0 deletions HeavenClient/Character/Look/PetLook.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,19 @@ namespace ms

int64_t get_serial() const;

Point<int16_t> get_position() const;

bool is_on_ground() const;

const PhysicsObject &get_phobj() const;

// PET_NAMECHANGE (172): the pet answers to its new name.
void set_name(const std::string &name);

// Dress it in the clothes `wear` (180xxxx) its owner's look gives
// its place in the list, or none for 0 (FUN_00703d15).
void set_wear(int32_t wear);

bool is_local() const;

Stance get_stance() const;
Expand All @@ -130,6 +140,10 @@ namespace ms
// once it moves, and now and then act on its own.
void update_acting(Point<int16_t> before);

// Draw the clothes' frame for the one `animation` shows.
void draw_dressing(const std::vector<Texture> &textures, const Animation &animation, const DrawArgument &args,
float alpha) const;

int32_t itemid;
std::string name;
int64_t serial;
Expand All @@ -151,6 +165,13 @@ namespace ms
// pet moves.
int16_t action;
Animation acting;
std::string acting_name;

// The clothes it wears, and their frames over each of its own
// (Character/PetEquip/<wear>.img/<itemid>/<animation>).
int32_t wear;
EnumMap<Stance, std::vector<Texture>> dressing;
std::vector<Texture> acting_dressing;
ChatBalloon balloon;
Animation effect;
bool effecting;
Expand Down
Loading
Loading