World of Warcraft's popular Grid and Clique addons for FFXI. Usage: /load greed Use the config XML to edit keybinds, colors, position, anchor point, etc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

565 lines
20 KiB

/**
* Copyright (c) 2011-2014 - Ashita Development Team
*
* Ashita is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Ashita is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Ashita. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Greed.h"
#include <algorithm>
#undef max
#undef min
D3DCOLOR darken(D3DCOLOR color)
{
return D3DCOLOR_ARGB(((color & 0xFF000000) >> 24), ((color & 0xFF0000) >> 16) / 3, ((color & 0xFF00) >> 8) / 3, (color & 0xFF) / 3);
}
D3DCOLOR brighten(D3DCOLOR color)
{
uint8_t alpha = (color & 0xFF000000) >> 24;
uint8_t r = (color & 0xFF0000) >> 16;
uint8_t g = (color & 0xFF00) >> 8;
uint8_t b = (color & 0xFF);
return D3DCOLOR_ARGB(alpha, r > 225 ? 255 : r + 30, g > 225 ? 255 : g + 30, b > 225 ? 255 : b + 30);
}
/**
* @brief Constructor and Deconstructor
*/
Greed::Greed(void)
: m_AshitaCore(NULL)
, m_PluginId(0)
, m_Direct3DDevice(NULL)
{ }
Greed::~Greed(void)
{ }
/**
* @brief Obtains the plugin data for this plugin.
*
* @return The PluginData structure for this plugin.
*/
plugininfo_t Greed::GetPluginInfo(void)
{
return (*g_PluginInfo);
}
/**
* @brief Initializes our plugin. This is the main call that happens when your plugin is loaded.
*
* @param ashitaCore The main Ashita Core object interface to interact with Ashita.
* @param scriptEngine The main script engine object interface to interact with the script engine.
* @param dwPluginId The base address of your plugin. This is used as the ID.
*
* @return True on success, false otherwise.
*
* @note If your plugin returns false here, it will be unloaded immediately!
*/
bool Greed::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
{
// Store the variables we are passed..
this->m_AshitaCore = core;
this->m_PluginId = id;
this->m_LogManager = log;
g_Greed = this;
LoadSettings();
return true;
}
/**
* @brief Releases this plugin. This is called when your plugin is unloaded.
*
* @note Your plugin should cleanup all its data here before it unloads. Anything such as:
* - Font objects.
* - Gui objects.
* - Bindings to the script engine (if you extended it any).
*/
void Greed::Release(void)
{
}
/**
* @brief Direct3D initialize call to prepare this plugin for Direct3D calls.
*
* @param lpDevice The Direct3D device currently wrapped by Ashita.
*
* @return True on success, false otherwise.
*
* @note Plugins that do not return true on this call will not receive any other
* Direct3D calls listed below!
*/
bool Greed::Direct3DInitialize(IDirect3DDevice8* device)
{
this->m_Direct3DDevice = device;
IFontObject* base = m_AshitaCore->GetFontManager()->Create("GreedBase");
base->SetFontFamily("Consolas");
base->SetFontHeight(10);
base->SetAutoResize(false);
base->GetBackground()->SetColor(D3DCOLOR_ARGB(0x60, 0x00, 0x00, 0x00));
base->GetBackground()->SetVisibility(true);
base->GetBackground()->SetWidth(308);
base->GetBackground()->SetHeight(config.Greedsize + config.spacing * 2);
base->SetAnchor((uint32_t)config.anchor);
base->SetAnchorParent((uint32_t)config.anchor);
base->SetText("");
base->SetPositionX(config.x);
base->SetPositionY(config.y);
base->SetVisibility(true);
IFontObject* prev = base;
IFontObject* rowBase = NULL;
for (int i = 0; i < 18; i++)
{
std::string texPath = m_AshitaCore->GetAshitaInstallPathA();
texPath.append("\\Resources\\Greed\\gradient.tga");
char alias[32];
sprintf_s(alias, sizeof alias, "GreedBG%d", i);
IFontObject* bg = m_AshitaCore->GetFontManager()->Create(alias);
bg->SetAutoResize(false);
bg->GetBackground()->SetColor(D3DCOLOR_ARGB(0xFF, config.rb, config.gb, config.bb));
bg->GetBackground()->SetWidth(config.Greedsize);
bg->GetBackground()->SetHeight(config.Greedsize);
bg->GetBackground()->SetVisibility(true);
bg->SetParent(prev);
bg->SetAnchor((uint32_t)config.anchor);
auto right = config.anchor & Ashita::FrameAnchor::Right;
auto bottom = config.anchor & Ashita::FrameAnchor::Bottom;
if (prev == base)
{
bg->SetAnchorParent((uint32_t)config.anchor);
bg->SetPositionX(right ? -config.spacing : config.spacing);
bg->SetPositionY(bottom ?
-config.spacing - (config.Greedsize + config.padding) * (i / 6) :
config.spacing + (config.Greedsize + config.padding) * (i / 6));
rowBase = bg;
}
else if (i == 6 || i == 12)
{
bg->SetParent(rowBase);
bg->SetAnchorParent(((int32_t)config.anchor ^ (int32_t)Ashita::FrameAnchor::Bottom));
bg->SetPositionX(0);
bg->SetPositionY(bottom ? -config.padding : config.padding);
rowBase = bg;
}
else
{
bg->SetAnchorParent(((int32_t)config.anchor ^ (int32_t)Ashita::FrameAnchor::Right));
bg->SetPositionX(right ? -config.padding : config.padding);
bg->SetPositionY(0);
}
bg->SetVisibility(true);
bg->SetMouseEventFunction([](int type, void* font, float xPos, float yPos){g_Greed->onClick(type, (IFontObject*)font, xPos, yPos); });
bg->GetBackground()->SetTextureFromFile(texPath.c_str());
sprintf_s(alias, sizeof alias, "GreedFG%d", i);
IFontObject* fg = m_AshitaCore->GetFontManager()->Create(alias);
fg->SetAutoResize(false);
fg->GetBackground()->SetColor(D3DCOLOR_ARGB(0xFF, config.rf, config.gf, config.bf));
fg->GetBackground()->SetWidth(config.Greedsize);
fg->GetBackground()->SetHeight(config.Greedsize);
fg->GetBackground()->SetVisibility(true);
fg->SetParent(bg);
fg->SetAnchor((uint32_t)Ashita::FrameAnchor::BottomLeft);
fg->SetAnchorParent((uint32_t)Ashita::FrameAnchor::BottomLeft);
fg->SetPositionX(0);
fg->SetPositionY(0);
fg->SetVisibility(true);
fg->GetBackground()->SetTextureFromFile(texPath.c_str());
sprintf_s(alias, sizeof alias, "GreedTX%d", i);
IFontObject* tx = m_AshitaCore->GetFontManager()->Create(alias);
tx->SetAutoResize(false);
tx->SetFontFamily("Consolas");
tx->SetFontHeight(config.fontsize);
tx->SetText("");
tx->SetColor(D3DCOLOR_ARGB(0xFF, config.rb, config.gb, config.bb));
tx->GetBackground()->SetVisibility(false);
tx->SetParent(bg);
tx->SetAnchor((uint32_t)Ashita::FrameAnchor::BottomLeft);
tx->SetAnchorParent((uint32_t)Ashita::FrameAnchor::BottomLeft);
tx->SetPositionX(config.padding);
tx->SetPositionY(-config.Greedsize / 2 - (5 * config.fontsize) / 6);
tx->SetVisibility(true);
sprintf_s(alias, sizeof alias, "GreedIndicatorTopLeft%d", i);
IFontObject* br = m_AshitaCore->GetFontManager()->Create(alias);
br->SetAutoResize(false);
br->GetBackground()->SetColor(D3DCOLOR_ARGB(0xFF, 0x80, 0x80, 0x00));
br->GetBackground()->SetWidth(config.Greedsize / 6);
br->GetBackground()->SetHeight(config.Greedsize / 6);
br->GetBackground()->SetVisibility(true);
br->SetParent(bg);
br->SetAnchor((uint32_t)Ashita::FrameAnchor::TopLeft);
br->SetAnchorParent((uint32_t)Ashita::FrameAnchor::TopLeft);
br->SetPositionX(0);
br->SetPositionY(0);
br->SetVisibility(false);
prev = bg;
}
return true;
}
/**
* @brief Direct3D release call to allow this plugin to cleanup any Direct3D objects.
*/
void Greed::Direct3DRelease(void)
{
m_AshitaCore->GetFontManager()->Delete("GreedBase");
for (int i = 0; i < 18; i++)
{
char alias[32];
sprintf_s(alias, sizeof alias, "GreedBG%d", i);
m_AshitaCore->GetFontManager()->Delete(alias);
sprintf_s(alias, sizeof alias, "GreedFG%d", i);
m_AshitaCore->GetFontManager()->Delete(alias);
sprintf_s(alias, sizeof alias, "GreedTX%d", i);
m_AshitaCore->GetFontManager()->Delete(alias);
sprintf_s(alias, sizeof alias, "GreedIndicatorTopLeft%d", i);
m_AshitaCore->GetFontManager()->Delete(alias);
}
}
/**
* @brief Direct3D prerender call to allow this plugin to prepare for rendering.
*
* @note This will only be called if you returned true in Direct3DInitialize!
*/
void Greed::Direct3DPreRender(void)
{
}
/**
* @brief Direct3D render call to allow this plugin to render any custom things.
*
* @note This will only be called if you returned true in Direct3DInitialize!
*/
void Greed::Direct3DRender(void)
{
int party = 0;
for (int i = 0; i < 18; i++)
{
char alias[32];
sprintf_s(alias, sizeof alias, "GreedBG%d", i);
IFontObject* bg = m_AshitaCore->GetFontManager()->Get(alias);
sprintf_s(alias, sizeof alias, "GreedFG%d", i);
IFontObject* fg = m_AshitaCore->GetFontManager()->Get(alias);
sprintf_s(alias, sizeof alias, "GreedTX%d", i);
IFontObject* tx = m_AshitaCore->GetFontManager()->Get(alias);
sprintf_s(alias, sizeof alias, "GreedIndicatorTopLeft%d", i);
IFontObject* br = m_AshitaCore->GetFontManager()->Get(alias);
if (!m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(i))
{
bg->SetVisibility(false);
fg->SetVisibility(false);
tx->SetVisibility(false);
br->SetVisibility(false);
targIdMap[bg] = 0;
}
else
{
bg->SetVisibility(true);
fg->SetVisibility(true);
tx->SetVisibility(true);
uint8_t hpp = m_AshitaCore->GetDataManager()->GetParty()->GetMemberCurrentHPP(i);
uint8_t job = m_AshitaCore->GetDataManager()->GetParty()->GetMemberMainJob(i);
uint16_t index = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(i);
if (config.jobColored && job <= (uint8_t)Ashita::FFXI::Enums::Jobs::RuneFencer)
{
bg->GetBackground()->SetColor(jobColors[job]);
fg->GetBackground()->SetColor(darken(jobColors[job]));
tx->SetColor(brighten(jobColors[job]));
}
fg->GetBackground()->SetHeight(bg->GetBackground()->GetHeight() * ((float)hpp / 100));
fg->SetAnchor((uint32_t)Ashita::FrameAnchor::BottomLeft);
std::string txString;
char rawString[16];
if (hpp > 90 || m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(i) != m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0))
{
sprintf_s(rawString, sizeof rawString, "%.*s", (config.Greedsize / config.fontsize) + 1, m_AshitaCore->GetDataManager()->GetParty()->GetMemberName(i));
txString.append(rawString);
}
else if (hpp == 0)
{
txString.append("DEAD");
}
else
{
uint32_t hp = m_AshitaCore->GetDataManager()->GetParty()->GetMemberCurrentHP(i);
float hpguess = (int)(hp / ((float)hpp / 100)) - hp;
sprintf_s(rawString, sizeof rawString, "-%.*f", hpguess > 1000 ? 1 : 0, hpguess > 1000 ? hpguess / 1000 : hpguess);
txString.append(rawString);
}
tx->SetText(txString.c_str());
if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(i) != m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0) ||
!(m_AshitaCore->GetDataManager()->GetEntity()->GetRenderFlags0(index) & 0x200) ||
m_AshitaCore->GetDataManager()->GetEntity()->GetDistance(index) > config.faderange)
{
bg->GetBackground()->SetColor((bg->GetBackground()->GetColor() & 0x00FFFFFF) | (0x10 << 24));
fg->GetBackground()->SetColor((fg->GetBackground()->GetColor() & 0x00FFFFFF) | (0x40 << 24));
tx->SetColor((tx->GetColor() & 0x00FFFFFF) | (0x40 << 24));
}
else
{
bg->GetBackground()->SetColor((bg->GetBackground()->GetColor() & 0x00FFFFFF) | (0xFF << 24));
fg->GetBackground()->SetColor((fg->GetBackground()->GetColor() & 0x00FFFFFF) | (0xFF << 24));
tx->SetColor((tx->GetColor() & 0x00FFFFFF) | (0xFF << 24));
}
if (m_AshitaCore->GetDataManager()->GetTarget()->GetTargetIndex() == index &&
m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(i) == m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0))
{
br->SetVisibility(true);
}
else
{
br->SetVisibility(false);
}
targIdMap[bg] = m_AshitaCore->GetDataManager()->GetEntity()->GetServerId(index);
party |= (i / 6);
}
}
IFontObject* base = m_AshitaCore->GetFontManager()->Get("GreedBase");
int maxmem = std::max(m_AshitaCore->GetDataManager()->GetParty()->GetAllianceParty0MemberCount(), std::max(m_AshitaCore->GetDataManager()->GetParty()->GetAllianceParty1MemberCount(),
m_AshitaCore->GetDataManager()->GetParty()->GetAllianceParty2MemberCount()));
base->GetBackground()->SetWidth(config.spacing * 2 + maxmem * config.Greedsize + (maxmem - 1) * config.padding);
base->GetBackground()->SetHeight(config.Greedsize + config.spacing * 2 + (party & 1 ? config.Greedsize + config.padding : 0) +
(party & 2 ? config.Greedsize + config.padding : 0));
base->SetAnchor((uint32_t)config.anchor);
}
void Greed::LoadSettings()
{
config.faderange = FADERANGE;
config.fontsize = FONTSIZE;
config.Greedsize = GreedSIZE;
config.padding = PADDING;
config.spacing = SPACING;
config.anchor = Ashita::FrameAnchor::BottomRight;
config.x = -132;
config.y = -16;
config.rf = 0x50;
config.gf = 0x28;
config.bf = 0x00;
config.rb = 0xFF;
config.gb = 0x80;
config.bb = 0x00;
config.jobColored = true;
char szConfigPath[MAX_PATH] = { 0 };
sprintf_s(szConfigPath, MAX_PATH, "%sConfig\\%s.xml", m_AshitaCore->GetAshitaInstallPathA(), g_PluginInfo->Name);
try
{
xmlFile = new rapidxml::file<>(szConfigPath);
settings.parse<0>(xmlFile->data());
}
catch (std::exception& e)
{
m_AshitaCore->GetChatManager()->Writef("Greed: Could not load settings: %s", e.what());
m_AshitaCore->GetChatManager()->Write("Greed: If this is your first time running Greed, you'll need to make a profile in Config/Greed.xml (use the profile in Docs for reference)");
return;
}
auto node = settings.first_node("settings");
if (node)
{
auto setNode = node->first_node("faderange");
if (setNode)
config.faderange = pow(atof(setNode->value()),2);
setNode = node->first_node("fontsize");
if (setNode)
config.fontsize = atoi(setNode->value());
setNode = node->first_node("Greedsize");
if (setNode)
config.Greedsize = atoi(setNode->value());
setNode = node->first_node("padding");
if (setNode)
config.padding = atoi(setNode->value());
setNode = node->first_node("spacing");
if (setNode)
config.spacing = atoi(setNode->value());
setNode = node->first_node("anchor");
if (setNode)
config.anchor = static_cast<Ashita::FrameAnchor>(atoi(setNode->value()));
setNode = node->first_node("xpos");
if (setNode)
config.x = atoi(setNode->value());
setNode = node->first_node("ypos");
if (setNode)
config.y = atoi(setNode->value());
setNode = node->first_node("fgred");
if (setNode)
config.rf = atoi(setNode->value());
setNode = node->first_node("fggreen");
if (setNode)
config.gf = atoi(setNode->value());
setNode = node->first_node("fgblue");
if (setNode)
config.bf = atoi(setNode->value());
setNode = node->first_node("bgred");
if (setNode)
config.rb = atoi(setNode->value());
setNode = node->first_node("bggreen");
if (setNode)
config.gb = atoi(setNode->value());
setNode = node->first_node("bgblue");
if (setNode)
config.bb = atoi(setNode->value());
setNode = node->first_node("jobcolored");
if (setNode)
config.jobColored = strncmp(setNode->value(),"true",setNode->value_size()) ? false : true;
}
}
/**
* @brief Gets the interface version this plugin was compiled with.
*
* @note This is a required export, your plugin must implement this!
*/
__declspec(dllexport) double __stdcall GetInterfaceVersion(void)
{
return ASHITA_INTERFACE_VERSION;
}
/**
* @brief Gets the plugin data for this plugin.
*
* @note This is a required export, your plugin must implement this!
*/
__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer)
{
g_PluginInfo = lpBuffer;
strcpy_s(g_PluginInfo->Name, sizeof(g_PluginInfo->Name), "Greed");
strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "kjLotus");
g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION;
g_PluginInfo->PluginVersion = 1.00f;
g_PluginInfo->Priority = 0;
}
/**
* @brief Creates an instance of this plugin object.
*
* @note This is a required export, your plugin must implement this!
*/
__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void)
{
return (IPlugin*)new Greed();
}
void Greed::onClick(int type, IFontObject* font, float xPos, float yPos)
{
if (xmlFile)
{
std::string job = jobs[m_AshitaCore->GetDataManager()->GetPlayer()->GetMainJob()];
std::transform(job.begin(), job.end(), job.begin(), ::tolower);
auto node = settings.first_node(job.c_str());
uint32_t targid;
try
{
targid = targIdMap.at(font);
}
catch (const std::out_of_range& e)
{
return;
}
if (node)
{
std::string click;
if (type == (int)Ashita::MouseInput::LeftClick)
click.append("lclick");
else if (type == (int)Ashita::MouseInput::RightClick)
click.append("rclick");
else if (type == (int)Ashita::MouseInput::MiddleClick)
click.append("mclick");
else if (type == (int)Ashita::MouseInput::X1Click)
click.append("button4");
else if (type == (int)Ashita::MouseInput::X2Click)
click.append("button5");
else
return;
for (auto clickNode = node->first_node(click.c_str()); clickNode; clickNode = clickNode->next_sibling(click.c_str()))
{
uint8_t modifiers = (GetAsyncKeyState(VK_CONTROL) & 0x8000 ? 1 : 0);
modifiers |= (GetAsyncKeyState(VK_MENU) & 0x8000 ? 2 : 0);
uint8_t foundModifiers = 0;
auto attr = clickNode->first_attribute("modifier");
for (auto attr = clickNode->first_attribute("modifier"); attr; attr = attr->next_attribute("modifier"))
{
if (strcmp(attr->value(), "ctrl") == 0)
foundModifiers |= 1;
else if (strcmp(attr->value(), "alt") == 0)
foundModifiers |= 2;
}
if (modifiers == foundModifiers)
{
std::string action = clickNode->value();
char cmd[64];
sprintf_s(cmd, sizeof cmd, "%s %d", action.c_str(), targid);
m_AshitaCore->GetChatManager()->QueueCommand(cmd, (int32_t)Ashita::CommandInputType::Menu);
return;
}
}
}
else
{
//no config for this job, default left click: target
if (type == 0 && !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
{
char cmd[64];
sprintf_s(cmd, sizeof cmd, "/target %d", targid);
m_AshitaCore->GetChatManager()->QueueCommand(cmd, (int32_t)Ashita::CommandInputType::Menu);
}
}
}
}