mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 01:23:51 +00:00
Clean README mentions and finalize current gameplay/UI fixes
This commit is contained in:
parent
16f8b0177e
commit
871da33942
6 changed files with 121 additions and 57 deletions
|
|
@ -5084,6 +5084,16 @@ void Application::updateQuestMarkers() {
|
|||
// Get NPC entity position
|
||||
auto entity = gameHandler->getEntityManager().getEntity(guid);
|
||||
if (!entity) continue;
|
||||
if (entity->getType() == game::ObjectType::UNIT) {
|
||||
auto unit = std::static_pointer_cast<game::Unit>(entity);
|
||||
std::string name = unit->getName();
|
||||
std::transform(name.begin(), name.end(), name.begin(),
|
||||
[](unsigned char c){ return static_cast<char>(std::tolower(c)); });
|
||||
if (name.find("spirit healer") != std::string::npos ||
|
||||
name.find("spirit guide") != std::string::npos) {
|
||||
continue; // Spirit healers/guides use their own white visual cue.
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 canonical(entity->getX(), entity->getY(), entity->getZ());
|
||||
glm::vec3 renderPos = coords::canonicalToRender(canonical);
|
||||
|
|
|
|||
|
|
@ -567,9 +567,22 @@ void GameHandler::update(float deltaTime) {
|
|||
}
|
||||
|
||||
// Update cast timer (Phase 3)
|
||||
if (pendingGameObjectInteractGuid_ != 0 &&
|
||||
(autoAttacking || !hostileAttackers_.empty())) {
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
addSystemChatMessage("Interrupted.");
|
||||
}
|
||||
if (casting && castTimeRemaining > 0.0f) {
|
||||
castTimeRemaining -= deltaTime;
|
||||
if (castTimeRemaining <= 0.0f) {
|
||||
if (pendingGameObjectInteractGuid_ != 0) {
|
||||
uint64_t interactGuid = pendingGameObjectInteractGuid_;
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
performGameObjectInteractionNow(interactGuid);
|
||||
}
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
|
|
@ -2636,6 +2649,7 @@ void GameHandler::selectCharacter(uint64_t characterGuid) {
|
|||
autoAttackTarget = 0;
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
castTimeTotal = 0.0f;
|
||||
playerDead_ = false;
|
||||
|
|
@ -6029,13 +6043,16 @@ void GameHandler::stopCasting() {
|
|||
return; // Not casting anything
|
||||
}
|
||||
|
||||
// Send cancel cast packet with current spell ID
|
||||
auto packet = CancelCastPacket::build(currentCastSpellId);
|
||||
socket->send(packet);
|
||||
// Send cancel cast packet only for real spell casts.
|
||||
if (pendingGameObjectInteractGuid_ == 0 && currentCastSpellId != 0) {
|
||||
auto packet = CancelCastPacket::build(currentCastSpellId);
|
||||
socket->send(packet);
|
||||
}
|
||||
|
||||
// Reset casting state
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
castTimeTotal = 0.0f;
|
||||
|
||||
|
|
@ -7872,10 +7889,14 @@ void GameHandler::castSpell(uint32_t spellId, uint64_t targetGuid) {
|
|||
|
||||
void GameHandler::cancelCast() {
|
||||
if (!casting) return;
|
||||
if (state == WorldState::IN_WORLD && socket) {
|
||||
// GameObject interaction cast is client-side timing only.
|
||||
if (pendingGameObjectInteractGuid_ == 0 &&
|
||||
state == WorldState::IN_WORLD && socket &&
|
||||
currentCastSpellId != 0) {
|
||||
auto packet = CancelCastPacket::build(currentCastSpellId);
|
||||
socket->send(packet);
|
||||
}
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
|
|
@ -8545,6 +8566,21 @@ void GameHandler::interactWithNpc(uint64_t guid) {
|
|||
}
|
||||
|
||||
void GameHandler::interactWithGameObject(uint64_t guid) {
|
||||
if (guid == 0) return;
|
||||
if (state != WorldState::IN_WORLD || !socket) return;
|
||||
if (casting && currentCastSpellId != 0) return; // don't overlap spell cast bar
|
||||
if (autoAttacking) {
|
||||
stopAutoAttack();
|
||||
}
|
||||
pendingGameObjectInteractGuid_ = guid;
|
||||
casting = true;
|
||||
currentCastSpellId = 0;
|
||||
castTimeTotal = 1.5f;
|
||||
castTimeRemaining = castTimeTotal;
|
||||
}
|
||||
|
||||
void GameHandler::performGameObjectInteractionNow(uint64_t guid) {
|
||||
if (guid == 0) return;
|
||||
if (state != WorldState::IN_WORLD || !socket) return;
|
||||
bool turtleMode = isActiveExpansion("turtle");
|
||||
|
||||
|
|
@ -8564,10 +8600,6 @@ void GameHandler::interactWithGameObject(uint64_t guid) {
|
|||
if (autoAttacking) {
|
||||
stopAutoAttack();
|
||||
}
|
||||
if (targetGuid != guid) {
|
||||
setTarget(guid);
|
||||
}
|
||||
|
||||
auto entity = entityManager.getEntity(guid);
|
||||
|
||||
auto packet = GameObjectUsePacket::build(guid);
|
||||
|
|
@ -9258,6 +9290,16 @@ void GameHandler::handleGossipMessage(network::Packet& packet) {
|
|||
bool hasAvailableQuest = false;
|
||||
bool hasRewardQuest = false;
|
||||
bool hasIncompleteQuest = false;
|
||||
auto questIconIsCompletable = [](uint32_t icon) {
|
||||
return icon == 5 || icon == 6 || icon == 10;
|
||||
};
|
||||
auto questIconIsIncomplete = [](uint32_t icon) {
|
||||
return icon == 3 || icon == 4;
|
||||
};
|
||||
auto questIconIsAvailable = [](uint32_t icon) {
|
||||
return icon == 2 || icon == 7 || icon == 8;
|
||||
};
|
||||
|
||||
for (const auto& questItem : currentGossip.quests) {
|
||||
// WotLK gossip questIcon is an integer enum, NOT a bitmask:
|
||||
// 2 = yellow ! (available, not yet accepted)
|
||||
|
|
@ -9265,9 +9307,9 @@ void GameHandler::handleGossipMessage(network::Packet& packet) {
|
|||
// 5 = gold ? (complete, ready to turn in)
|
||||
// Bit-masking these values is wrong: 4 & 0x04 = true, treating incomplete
|
||||
// quests as completable and causing the server to reject the turn-in request.
|
||||
bool isCompletable = (questItem.questIcon == 5); // Gold ? = can turn in
|
||||
bool isIncomplete = (questItem.questIcon == 4); // Gray ? = in progress
|
||||
bool isAvailable = (questItem.questIcon == 2); // Yellow ! = available
|
||||
bool isCompletable = questIconIsCompletable(questItem.questIcon);
|
||||
bool isIncomplete = questIconIsIncomplete(questItem.questIcon);
|
||||
bool isAvailable = questIconIsAvailable(questItem.questIcon);
|
||||
|
||||
hasAvailableQuest |= isAvailable;
|
||||
hasRewardQuest |= isCompletable;
|
||||
|
|
@ -9290,7 +9332,9 @@ void GameHandler::handleGossipMessage(network::Packet& packet) {
|
|||
if (hasRewardQuest) derivedStatus = QuestGiverStatus::REWARD;
|
||||
else if (hasAvailableQuest) derivedStatus = QuestGiverStatus::AVAILABLE;
|
||||
else if (hasIncompleteQuest) derivedStatus = QuestGiverStatus::INCOMPLETE;
|
||||
npcQuestStatus_[currentGossip.npcGuid] = derivedStatus;
|
||||
if (derivedStatus != QuestGiverStatus::NONE) {
|
||||
npcQuestStatus_[currentGossip.npcGuid] = derivedStatus;
|
||||
}
|
||||
}
|
||||
|
||||
// Play NPC greeting voice
|
||||
|
|
@ -9371,10 +9415,20 @@ void GameHandler::handleQuestgiverQuestList(network::Packet& packet) {
|
|||
bool hasAvailableQuest = false;
|
||||
bool hasRewardQuest = false;
|
||||
bool hasIncompleteQuest = false;
|
||||
auto questIconIsCompletable = [](uint32_t icon) {
|
||||
return icon == 5 || icon == 6 || icon == 10;
|
||||
};
|
||||
auto questIconIsIncomplete = [](uint32_t icon) {
|
||||
return icon == 3 || icon == 4;
|
||||
};
|
||||
auto questIconIsAvailable = [](uint32_t icon) {
|
||||
return icon == 2 || icon == 7 || icon == 8;
|
||||
};
|
||||
|
||||
for (const auto& questItem : currentGossip.quests) {
|
||||
bool isCompletable = (questItem.questIcon == 5 || questItem.questIcon == 10);
|
||||
bool isIncomplete = (questItem.questIcon == 3 || questItem.questIcon == 4);
|
||||
bool isAvailable = (questItem.questIcon == 2 || questItem.questIcon == 7 || questItem.questIcon == 8);
|
||||
bool isCompletable = questIconIsCompletable(questItem.questIcon);
|
||||
bool isIncomplete = questIconIsIncomplete(questItem.questIcon);
|
||||
bool isAvailable = questIconIsAvailable(questItem.questIcon);
|
||||
hasAvailableQuest |= isAvailable;
|
||||
hasRewardQuest |= isCompletable;
|
||||
hasIncompleteQuest |= isIncomplete;
|
||||
|
|
@ -9384,7 +9438,9 @@ void GameHandler::handleQuestgiverQuestList(network::Packet& packet) {
|
|||
if (hasRewardQuest) derivedStatus = QuestGiverStatus::REWARD;
|
||||
else if (hasAvailableQuest) derivedStatus = QuestGiverStatus::AVAILABLE;
|
||||
else if (hasIncompleteQuest) derivedStatus = QuestGiverStatus::INCOMPLETE;
|
||||
npcQuestStatus_[currentGossip.npcGuid] = derivedStatus;
|
||||
if (derivedStatus != QuestGiverStatus::NONE) {
|
||||
npcQuestStatus_[currentGossip.npcGuid] = derivedStatus;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Questgiver quest list: npc=0x", std::hex, currentGossip.npcGuid, std::dec,
|
||||
|
|
@ -9990,6 +10046,7 @@ void GameHandler::handleNewWorld(network::Packet& packet) {
|
|||
stopAutoAttack();
|
||||
casting = false;
|
||||
currentCastSpellId = 0;
|
||||
pendingGameObjectInteractGuid_ = 0;
|
||||
castTimeRemaining = 0.0f;
|
||||
|
||||
// Send MSG_MOVE_WORLDPORT_ACK to tell the server we're ready
|
||||
|
|
|
|||
|
|
@ -1649,7 +1649,19 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
|||
characterShader->setUniform("uUnlit", unlit ? 1 : 0);
|
||||
float emissiveBoost = 1.0f;
|
||||
glm::vec3 emissiveTint(1.0f, 1.0f, 1.0f);
|
||||
if (unlit) {
|
||||
// Keep custom warm/flicker treatment narrowly scoped to kobold candle flames.
|
||||
bool koboldCandleFlame = false;
|
||||
if (colorKeyBlack) {
|
||||
std::string modelKey = gpuModel.data.name;
|
||||
std::transform(modelKey.begin(), modelKey.end(), modelKey.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
koboldCandleFlame =
|
||||
(modelKey.find("kobold") != std::string::npos) &&
|
||||
((modelKey.find("candle") != std::string::npos) ||
|
||||
(modelKey.find("torch") != std::string::npos) ||
|
||||
(modelKey.find("mine") != std::string::npos));
|
||||
}
|
||||
if (unlit && koboldCandleFlame) {
|
||||
using clock = std::chrono::steady_clock;
|
||||
float t = std::chrono::duration<float>(clock::now().time_since_epoch()).count();
|
||||
float phase = static_cast<float>(batch.submeshId) * 0.31f;
|
||||
|
|
|
|||
|
|
@ -4826,48 +4826,27 @@ void GameScreen::renderQuestOfferRewardWindow(game::GameHandler& gameHandler) {
|
|||
}
|
||||
}
|
||||
|
||||
// Render item with icon
|
||||
// Render item with icon + visible selectable label
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
if (ImGui::Selectable("##reward", selected, 0, ImVec2(0, 40))) {
|
||||
std::string label;
|
||||
if (info && info->valid && !info->name.empty()) {
|
||||
label = info->name;
|
||||
} else {
|
||||
label = "Item " + std::to_string(item.itemId);
|
||||
}
|
||||
if (item.count > 1) {
|
||||
label += " x" + std::to_string(item.count);
|
||||
}
|
||||
if (ImGui::Selectable(label.c_str(), selected, 0, ImVec2(0, 24))) {
|
||||
selectedChoice = static_cast<int>(i);
|
||||
}
|
||||
|
||||
// Draw icon and text over the selectable
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::GetItemRectSize().x + 4);
|
||||
|
||||
if (ImGui::IsItemHovered() && iconTex) {
|
||||
ImGui::SetTooltip("Reward option");
|
||||
}
|
||||
if (iconTex) {
|
||||
ImGui::Image((void*)(intptr_t)iconTex, ImVec2(36, 36));
|
||||
ImGui::SameLine();
|
||||
ImGui::Image((void*)(intptr_t)iconTex, ImVec2(18, 18));
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
if (info && info->valid) {
|
||||
ImGui::TextColored(qualityColor, "%s", info->name.c_str());
|
||||
if (item.count > 1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.7f), "x%u", item.count);
|
||||
}
|
||||
// Show stats
|
||||
if (info->armor > 0 || info->stamina > 0 || info->strength > 0 ||
|
||||
info->agility > 0 || info->intellect > 0 || info->spirit > 0) {
|
||||
std::string stats;
|
||||
if (info->armor > 0) stats += std::to_string(info->armor) + " Armor ";
|
||||
if (info->stamina > 0) stats += "+" + std::to_string(info->stamina) + " Sta ";
|
||||
if (info->strength > 0) stats += "+" + std::to_string(info->strength) + " Str ";
|
||||
if (info->agility > 0) stats += "+" + std::to_string(info->agility) + " Agi ";
|
||||
if (info->intellect > 0) stats += "+" + std::to_string(info->intellect) + " Int ";
|
||||
if (info->spirit > 0) stats += "+" + std::to_string(info->spirit) + " Spi ";
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s", stats.c_str());
|
||||
}
|
||||
} else {
|
||||
ImGui::TextColored(qualityColor, "Item %u", item.itemId);
|
||||
if (item.count > 0) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.7f), "x%u", item.count);
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue