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
4 changes: 3 additions & 1 deletion HeavenClient/Graphics/Color.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ namespace ms
FAMILYBLUE,
MEDALTEAL,
SPOUSEPINK,
ITEMLINK,
NUM_COLORS
};

Expand Down Expand Up @@ -255,7 +256,8 @@ namespace ms
{1.00f, 0.78f, 0.00f}, // Script gold (#FFC600, the floating script lines)
{0.64f, 0.94f, 1.00f}, // Family blue (#A4F0FF, v83 font 0x10: an empty junior's box in the Family Tree)
{0.20f, 0.43f, 0.50f}, // Medal teal (#346E80, a title's name in v83's title window)
{1.00f, 0.44f, 0.75f} // Spouse pink (#FF71BF, v83 chat font 6: spouse chat)
{1.00f, 0.44f, 0.75f}, // Spouse pink (#FF71BF, v83 chat font 6: spouse chat)
{0.42f, 0.30f, 0.89f} // Item link (#6C4CE3, v83 chat font ctx+0xc20: an item megaphone's [item])
};

// Create a color by an array of real numbers [0.0f, 1.0f]
Expand Down
4 changes: 3 additions & 1 deletion HeavenClient/IO/Components/Tooltip.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ namespace ms
WEDDINGREGISTRY,
USERLIST,
MEDALS,
TIMEDQUESTS
TIMEDQUESTS,
// An item a chat log line links, shown below the click.
CHATBAR
};

virtual ~Tooltip()
Expand Down
8 changes: 8 additions & 0 deletions HeavenClient/IO/UIStateGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "FamilyActions.h"
#include "Components/TooltipBox.h"

#include "../Util/ChatLinks.h"

#include "UITypes/UIBuffList.h"
#include "UITypes/UIPartyHP.h"
#include "UITypes/UIPartySearch.h"
Expand Down Expand Up @@ -136,6 +138,8 @@ namespace ms
return Tooltip::Parent::ITEMSEARCHRESULT;
case UIElement::Type::USERLIST:
return Tooltip::Parent::USERLIST;
case UIElement::Type::CHATBAR:
return Tooltip::Parent::CHATBAR;
default:
return Tooltip::Parent::NONE;
}
Expand All @@ -157,6 +161,8 @@ namespace ms
// The Owl of Minerva's results put it 20 right of and below the cursor (FUN_008a45b9), as
// does the User List (0x91d82f).
const Point<int16_t> OWL_TOOLTIP_POS = Point<int16_t>(20, 20) - tooltip::OFFSET;
// A chat log line's item goes 20 below the cursor (FUN_008f5b20).
const Point<int16_t> CHAT_TOOLTIP_POS = Point<int16_t>(0, chat_link::BELOW) - tooltip::OFFSET;

Point<int16_t> tooltip_pos(Tooltip::Parent parent)
{
Expand All @@ -169,6 +175,8 @@ namespace ms
case Tooltip::Parent::ITEMSEARCHRESULT:
case Tooltip::Parent::USERLIST:
return OWL_TOOLTIP_POS;
case Tooltip::Parent::CHATBAR:
return CHAT_TOOLTIP_POS;
default:
return TOOLTIP_POS;
}
Expand Down
92 changes: 89 additions & 3 deletions HeavenClient/IO/UITypes/UIChatBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "../../Graphics/GraphicsGL.h"
#include "../../Net/Packets/MessagingPackets.h"
#include "../../Util/CharacterName.h"
#include "../../Util/ChatLinks.h"
#include "../../Util/ChatWrap.h"
#include "../../Util/NxFiles.h"

Expand Down Expand Up @@ -563,6 +564,10 @@ namespace ms
}

shown.text.draw(position + Point<int16_t>(3 + indent, top - TEXT_RAISE));

// v83 draws the linked item's name over itself in violet.
if (shown.link)
shown.link->draw(position + Point<int16_t>(3 + indent + shown.link_x, top - TEXT_RAISE));
}

Point<int16_t> bar = position + get_scrollbar_pos();
Expand Down Expand Up @@ -681,6 +686,14 @@ namespace ms
bool released = !clicking && scrollbar_pressed;
scrollbar_pressed = clicking;

if (link_click)
{
Point<int16_t> moved = cursorpos - *link_click;

if (!chat_link::keeps(moved.x(), moved.y()))
hide_link();
}

if (thumb_dragging)
{
if (clicking)
Expand Down Expand Up @@ -784,7 +797,22 @@ namespace ms
ScrollPart part = scroll_part_at(cursorpos);

if (part == ScrollPart::NONE)
{
// The button going down on a row that links an item shows it
// (FUN_008d5f5c).
if (pressed)
{
std::optional<size_t> row = row_at(cursorpos);

if (row && rowtexts[*row].item)
{
UI::get().show_item(Tooltip::Parent::CHATBAR, *rowtexts[*row].item);
link_click = cursorpos;
}
}

return UIElement::send_cursor(clicking, cursorpos);
}

if (get_scrollrange() < 2)
return Cursor::State::IDLE;
Expand Down Expand Up @@ -830,6 +858,7 @@ namespace ms
held_part = ScrollPart::NONE;
edge_dragging = false;
combo_hovered = false;
hide_link();
}

UIElement::Type UIChatBar::get_type() const
Expand Down Expand Up @@ -858,7 +887,14 @@ namespace ms
add_line(line, type, channel, ear);
}

void UIChatBar::add_line(const std::string &line, LineType type, int8_t channel, bool ear)
void UIChatBar::send_linked(const std::string &line, LineType type, int8_t channel, bool ear,
const storage_contents::Stored &item, size_t from, size_t length)
{
add_line(line, type, channel, ear, std::make_shared<const storage_contents::Stored>(item), from, length);
}

void UIChatBar::add_line(const std::string &line, LineType type, int8_t channel, bool ear,
std::shared_ptr<const storage_contents::Stored> item, size_t from, size_t length)
{
Color::Name color;
Color strip;
Expand Down Expand Up @@ -964,11 +1000,27 @@ namespace ms
type == LineType::SUPER_MEGAPHONE || type == LineType::ITEM_MEGAPHONE ||
type == LineType::MEGAPHONE_PREVIEW || type == LineType::GACHAPON;

bool first = true;

for (const auto& row : ChatWrap::wrap(line, indent, fit))
{
rowtexts.push_back({ Text(Text::Font::A12M, Text::Alignment::LEFT, color, row), strip, channel, ear, row,
claimable });
Text text(Text::Font::A12M, Text::Alignment::LEFT, color, row);
std::optional<Text> link;
int16_t link_x = 0;

if (first)
{
if (size_t shown = chat_link::shown(row.size(), from, length))
{
link = Text(Text::Font::A12M, Text::Alignment::LEFT, Color::Name::ITEMLINK,
row.substr(from, shown));
link_x = static_cast<int16_t>(text.advance(from));
}
}

rowtexts.push_back({ text, strip, channel, ear, row, claimable, item, link, link_x });
channel = -1;
first = false;
}

while (rowtexts.size() > MAX_ROWS)
Expand Down Expand Up @@ -1204,6 +1256,40 @@ namespace ms
return Rectangle<int16_t>(left, left + COMBO_LIST_WIDTH, COMBO.top() - height, COMBO.top());
}

std::optional<size_t> UIChatBar::row_at(Point<int16_t> cursorpos) const
{
Point<int16_t> cursor = cursorpos - position;

if (cursor.x() < 0 || cursor.x() >= chat_link::HOT_WIDTH)
return {};

int16_t logbottom = get_logtop() + get_logheight();

for (int16_t i = 0; i < get_logrows(); i++)
{
int16_t row = rowpos - i;

if (row < 0 || row > rowmax)
break;

int16_t top = logbottom - CHATROWHEIGHT * (i + 1);

if (cursor.y() >= top && cursor.y() < top + CHATROWHEIGHT)
return static_cast<size_t>(row);
}

return {};
}

void UIChatBar::hide_link()
{
if (link_click)
{
UI::get().clear_tooltip(Tooltip::Parent::CHATBAR);
link_click.reset();
}
}

std::optional<size_t> UIChatBar::combo_row_at(Point<int16_t> cursorpos) const
{
Rectangle<int16_t> list = combo_list_bounds();
Expand Down
24 changes: 23 additions & 1 deletion HeavenClient/IO/UITypes/UIChatBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <cstdint>
#include <deque>
#include <memory>
#include <optional>
#include <vector>

Expand All @@ -34,6 +35,7 @@
#include "../Components/ChatTarget.h"
#include "../Components/Textfield.h"

#include "../../Net/Handlers/StorageContents.h"
#include "../../Template/EnumMap.h"

namespace ms
Expand Down Expand Up @@ -118,6 +120,12 @@ namespace ms
// and whether they can be whispered back.
void send_megaphone(const std::string &line, LineType type, int8_t channel, bool ear);

// A line that links an item (BROADCAST_MSG types 6, 8 and 11): a
// click on any of its rows shows the item. The part of `length` from
// `from` is the item's name, drawn violet on the first row.
void send_linked(const std::string &line, LineType type, int8_t channel, bool ear,
const storage_contents::Stored &item, size_t from = 0, size_t length = 0);

// The log's rows a report can quote, oldest first: v83 takes the
// rows of its chat kinds 0 to 4, 0xd to 0xf and 0x12 to 0x16
// (0x8d468d), which leaves out alliance, spouse and GM chat and the
Expand Down Expand Up @@ -329,13 +337,27 @@ namespace ms
// The row as written, and whether a report can quote it
std::string line;
bool claimable;
// The item the line links, if any, and the item's name drawn
// over the first row from link_x
std::shared_ptr<const storage_contents::Stored> item;
std::optional<Text> link;
int16_t link_x;
};
// Oldest first; a wrapped row keeps its strip when old rows leave.
std::deque<ChatRow> rowtexts;
// The channel tags, with and without the ear, and their digits
Texture channel_tags[2];
Texture channel_digits[10];

void add_line(const std::string &line, LineType type, int8_t channel, bool ear);
// Where the item shown by a click on a row was clicked, while it
// shows.
std::optional<Point<int16_t>> link_click;

void add_line(const std::string &line, LineType type, int8_t channel, bool ear,
std::shared_ptr<const storage_contents::Stored> item = nullptr, size_t from = 0,
size_t length = 0);
// The row under the cursor, if the log shows one there.
std::optional<size_t> row_at(Point<int16_t> cursorpos) const;
void hide_link();
};
}
43 changes: 29 additions & 14 deletions HeavenClient/Net/Handlers/MessagingHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,20 @@ namespace ms
chatbar->send_chatline(message, UIChatBar::LineType::SKILL);
break;
case 6:
// An item id, linking the item to the line when not 0
recv.read_int();
{
// An item id, linking the item to the line when not 0;
// nothing in the line's look shows it.
int32_t itemid = recv.read_int();

if (chatbar)
chatbar->send_chatline(message, UIChatBar::LineType::BLUE);
{
if (itemid)
chatbar->send_linked(message, UIChatBar::LineType::BLUE, -1, false, { itemid, 1 });
else
chatbar->send_chatline(message, UIChatBar::LineType::BLUE);
}
break;
}
case 7:
{
// The NPC says it in a dialog with OK, which answers
Expand All @@ -587,15 +595,23 @@ namespace ms
int8_t channel = recv.read_byte();
bool ear = type == 9 || recv.read_bool();

// The item comes last, after its kind; only its name is shown.
// The item comes last; its name goes before the text, and a
// click on the line shows it.
if (type == 8 && recv.read_bool())
{
recv.read_byte();
message = Megaphones::with_item(message, ItemData::get(recv.read_int()).get_name());
}

if (chatbar)
storage_contents::Stored item = storage_contents::read_item(recv);
std::string name = ItemData::get(item.itemid).get_name();
size_t at = Megaphones::item_at(message);
message = Megaphones::with_item(message, name);

// "[Name]", brackets and all
if (chatbar)
chatbar->send_linked(message, UIChatBar::LineType::ITEM_MEGAPHONE, channel, ear, item, at,
name.size() + 2);
} else if (chatbar)
{
chatbar->send_megaphone(message, UIChatBar::LineType::ITEM_MEGAPHONE, channel, ear);
}

warn(message);
break;
Expand All @@ -604,15 +620,14 @@ namespace ms
{
// The winner's channel (-1 would be the Cash Shop Surprise,
// which RustMS doesn't send), the machine's town, then the
// prize after its kind; only its name is shown.
// prize, which a click on the line shows.
recv.read_int();
std::string town = recv.read_string();
recv.read_byte();
std::string item = ItemData::get(recv.read_int()).get_name();
std::string line = Megaphones::gachapon(message, item, town);
storage_contents::Stored item = storage_contents::read_item(recv);
std::string line = Megaphones::gachapon(message, ItemData::get(item.itemid).get_name(), town);

if (chatbar)
chatbar->send_chatline(line, UIChatBar::LineType::GACHAPON);
chatbar->send_linked(line, UIChatBar::LineType::GACHAPON, -1, false, item);

warn(line);
break;
Expand Down
35 changes: 35 additions & 0 deletions HeavenClient/Util/ChatLinks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <algorithm>
#include <cstddef>
#include <cstdint>

namespace ms
{
// How v83 links an item to a chat log line (BROADCAST_MSG types 6, 8 and
// 11): every row of the line carries the item, and a click on one shows
// it (FUN_008d5f5c).
namespace chat_link
{
// A row is hot left of this, the log's whole width.
constexpr int16_t HOT_WIDTH = 0x244;
// The tooltip goes 20 below the click (FUN_008f5b20)...
constexpr int16_t BELOW = 0x14;
// ...and stays while the cursor is in the 40x40 square around the
// click, the right and bottom edges left out (PtInRect, 0x8d804e).
// `dx` and `dy` are how far the cursor is from the click.
constexpr int16_t KEEP = 0x14;

inline bool keeps(int16_t dx, int16_t dy)
{
return dx >= -KEEP && dx < KEEP && dy >= -KEEP && dy < KEEP;
}

// How much of the part from `from`, `length` long, a row of
// `row_size` shows; only the first row draws it violet.
inline size_t shown(size_t row_size, size_t from, size_t length)
{
return from >= row_size ? 0 : std::min(length, row_size - from);
}
}
}
Loading
Loading